การเข้ารหัสทั้งดิสก์เป็นกระบวนการเข้ารหัสข้อมูลผู้ใช้ทั้งหมดในอุปกรณ์ Android โดยใช้คีย์ที่เข้ารหัส เมื่อเข้ารหัสอุปกรณ์แล้ว ระบบจะเข้ารหัสข้อมูลทั้งหมดที่ผู้ใช้สร้างขึ้นโดยอัตโนมัติก่อนที่จะบันทึกลงในดิสก์ และการอ่านทั้งหมดจะถอดรหัสข้อมูลโดยอัตโนมัติก่อนที่จะส่งกลับไปยังกระบวนการเรียกใช้
การเข้ารหัสทั้งดิสก์เปิดตัวใน Android 4.4 แต่ Android 5.0 เปิดตัวฟีเจอร์ใหม่ต่อไปนี้
- สร้างการเข้ารหัสที่รวดเร็ว ซึ่งจะเข้ารหัสเฉพาะบล็อกที่ใช้ในพาร์ติชันข้อมูลเพื่อหลีกเลี่ยงการบูตครั้งแรกที่ใช้เวลานาน ปัจจุบันมีเพียงระบบไฟล์ ext4 และ f2fs เท่านั้นที่รองรับการเข้ารหัสอย่างรวดเร็ว
- เพิ่ม
forceencrypt
Flag fstab เพื่อเข้ารหัสในการบูตครั้งแรก - รองรับรูปแบบและการเข้ารหัสโดยไม่ต้องใช้รหัสผ่าน
- เพิ่มพื้นที่เก็บข้อมูลที่ใช้ฮาร์ดแวร์สนับสนุนสำหรับคีย์การเข้ารหัสโดยใช้ความสามารถในการลงนามของสภาพแวดล้อมการดำเนินการที่เชื่อถือได้ (TEE) (เช่น ใน TrustZone) ดูรายละเอียดเพิ่มเติมได้ที่การจัดเก็บคีย์ที่เข้ารหัส
ข้อควรระวัง: อุปกรณ์ที่อัปเกรดเป็น Android 5.0 แล้วเข้ารหัสสามารถเปลี่ยนกลับไปเป็นสถานะที่ไม่ได้เข้ารหัสได้ด้วยการรีเซ็ตข้อมูลเป็นค่าเริ่มต้น อุปกรณ์ Android 5.0 ใหม่ที่เข้ารหัสเมื่อบูตครั้งแรกจะเปลี่ยนกลับไปเป็นสถานะที่ไม่ได้เข้ารหัสไม่ได้
วิธีการทํางานของการเข้ารหัสดิสก์เต็มรูปแบบของ Android
การเข้ารหัสดิสก์ทั้งเครื่องของ Android อิงตาม dm-crypt
ซึ่งเป็นฟีเจอร์เคอร์เนลที่ทำงานในระดับอุปกรณ์บล็อก ด้วยเหตุนี้ การเข้ารหัสจึงใช้ได้กับ Embedded MultiMediaCard (eMMC) และอุปกรณ์แฟลชที่คล้ายกันซึ่งแสดงตัวตนต่อเคอร์เนลเป็นอุปกรณ์บล็อก YAFFS ไม่สามารถเข้ารหัสได้ เนื่องจากจะสื่อสารกับชิปแฟลช NAND โดยตรง
อัลกอริทึมการเข้ารหัสคือ Advanced Encryption Standard (AES) 128 บิตที่มีการเข้ารหัสบล็อกแบบเชน (CBC) และ ESSIV:SHA256 คีย์หลักได้รับการเข้ารหัสด้วย AES 128 บิตผ่านการเรียกใช้ไลบรารี OpenSSL คุณต้องใช้คีย์ขนาด 128 บิตขึ้นไป (หรือจะใช้ 256 บิตก็ได้)
หมายเหตุ: OEM สามารถใช้ 128 บิตขึ้นไปเพื่อเข้ารหัสคีย์หลักได้
ในรุ่น Android 5.0 สถานะการเข้ารหัสมี 4 ประเภทดังนี้
- ค่าเริ่มต้น
- PIN
- รหัสผ่าน
- รูปแบบ
เมื่อบูตเครื่องครั้งแรก อุปกรณ์จะสร้างคีย์หลัก 128 บิตแบบสุ่ม แล้วแฮชด้วยรหัสผ่านเริ่มต้นและ Salt ที่เก็บไว้ รหัสผ่านเริ่มต้นคือ "default_password" อย่างไรก็ตาม แฮชที่ได้จะได้รับการรับรองผ่าน TEE (เช่น TrustZone) ด้วยเช่นกัน ซึ่งจะใช้แฮชของลายเซ็นเพื่อเข้ารหัสคีย์หลัก
คุณดูรหัสผ่านเริ่มต้นที่กำหนดไว้ในไฟล์ cryptfs.cpp ของโปรเจ็กต์โอเพนซอร์ส Android ได้
เมื่อผู้ใช้ตั้งค่า PIN/พาสคีย์หรือรหัสผ่านในอุปกรณ์ ระบบจะเข้ารหัสและจัดเก็บเฉพาะคีย์ 128 บิตอีกครั้ง (เช่น การเปลี่ยนแปลง PIN/รหัสผ่าน/รูปแบบของผู้ใช้จะไม่ทําให้ต้องมีการเข้ารหัสข้อมูลผู้ใช้อีกครั้ง) โปรดทราบว่าอุปกรณ์ที่มีการจัดการอาจอยู่ภายใต้ข้อจำกัดของ PIN, รูปแบบ หรือรหัสผ่าน
init
และ vold
เป็นผู้จัดการการเข้ารหัส
init
เรียก vold
และ vold จะตั้งค่าพร็อพเพอร์ตี้เพื่อทริกเกอร์เหตุการณ์ใน init ส่วนอื่นๆ ของระบบจะดูพร็อพเพอร์ตี้เพื่อดำเนินการต่างๆ ด้วย เช่น รายงานสถานะ ขอรหัสผ่าน หรือแจ้งให้รีเซ็ตเป็นค่าเริ่มต้นในกรณีที่มีข้อผิดพลาดร้ายแรง หากต้องการเรียกใช้ฟีเจอร์การเข้ารหัสใน vold
ระบบจะใช้คำสั่ง cryptfs
ของเครื่องมือบรรทัดคำสั่ง vdc
ซึ่งได้แก่ checkpw
,
restart
, enablecrypto
, changepw
,
cryptocomplete
, verifypw
, setfield
,
getfield
, mountdefaultencrypted
, getpwtype
,
getpw
และ clearpw
หากต้องการเข้ารหัส ถอดรหัส หรือล้างข้อมูล /data
/data
ต้องไม่ได้รับการต่อเชื่อม อย่างไรก็ตาม หากต้องการแสดงอินเทอร์เฟซผู้ใช้ (UI) ใดๆ เฟรมเวิร์กจะต้องเริ่มต้นและเฟรมเวิร์กต้องใช้ /data
เพื่อทํางาน ระบบจะต่อเชื่อมระบบไฟล์ชั่วคราวใน /data
เพื่อแก้ปัญหานี้
ซึ่งจะช่วยให้ Android แสดงข้อความแจ้งให้ป้อนรหัสผ่าน แสดงความคืบหน้า หรือแนะนำให้ล้างข้อมูลได้ตามต้องการ แต่มีข้อจำกัดว่าหากต้องการเปลี่ยนจากไฟล์ระบบชั่วคราวเป็นไฟล์ระบบ /data
จริง ระบบต้องหยุดทุกกระบวนการที่มีไฟล์เปิดอยู่ในไฟล์ระบบชั่วคราวและเริ่มกระบวนการเหล่านั้นอีกครั้งในไฟล์ระบบ /data
จริง โดยบริการทั้งหมดต้องอยู่ในกลุ่มใดกลุ่มหนึ่งต่อไปนี้ core
, main
และ late_start
core
: ไม่ปิดเครื่องหลังจากเริ่มต้นmain
: ปิดเครื่องแล้วเปิดขึ้นมาใหม่หลังจากป้อนรหัสผ่านของดิสก์late_start
: ไม่เริ่มต้นจนกว่าจะมีการถอดรหัสและต่อเชื่อม/data
หากต้องการทริกเกอร์การดำเนินการเหล่านี้ ระบบจะตั้งค่าพร็อพเพอร์ตี้ vold.decrypt
เป็นสตริงต่างๆ
หากต้องการหยุดและเริ่มบริการใหม่ คำสั่ง init
มีดังนี้
class_reset
: หยุดบริการ แต่อนุญาตให้รีสตาร์ทด้วย class_startclass_start
: รีสตาร์ทบริการclass_stop
: หยุดบริการและเพิ่ม FlagSVC_DISABLED
บริการที่หยุดทำงานจะไม่ตอบสนองต่อclass_start
โฟลว์
อุปกรณ์ที่เข้ารหัสมีขั้นตอน 4 ขั้นตอน อุปกรณ์จะได้รับการเข้ารหัสเพียงครั้งเดียว จากนั้นระบบจะดำเนินการตามขั้นตอนการบูตตามปกติ
- เข้ารหัสอุปกรณ์ที่ไม่ได้เข้ารหัสก่อนหน้านี้ โดยทำดังนี้
- เข้ารหัสอุปกรณ์ใหม่ด้วย
forceencrypt
: การเข้ารหัสแบบบังคับ เมื่อบูตครั้งแรก (เริ่มตั้งแต่ Android L) - เข้ารหัสอุปกรณ์ที่มีอยู่: การเข้ารหัสที่ผู้ใช้เริ่ม (Android K และเก่ากว่า)
- เข้ารหัสอุปกรณ์ใหม่ด้วย
- วิธีบูตอุปกรณ์ที่เข้ารหัส
- การเริ่มอุปกรณ์ที่เข้ารหัสโดยไม่มีรหัสผ่าน: การบูตอุปกรณ์ที่เข้ารหัสซึ่งไม่มีการตั้งรหัสผ่าน (เกี่ยวข้องกับอุปกรณ์ที่ใช้ Android 5.0 ขึ้นไป)
- การเริ่มอุปกรณ์ที่เข้ารหัสด้วยรหัสผ่าน: การบูตอุปกรณ์ที่เข้ารหัสซึ่งมีรหัสผ่านที่ตั้งไว้
นอกเหนือจากขั้นตอนเหล่านี้แล้ว อุปกรณ์อาจเข้ารหัส /data
ไม่ได้ด้วย
แต่ละขั้นตอนมีคำอธิบายโดยละเอียดด้านล่าง
เข้ารหัสอุปกรณ์เครื่องใหม่ด้วย forceencrypt
การบูตครั้งแรกนี้เป็นการเปิดเครื่องตามปกติของอุปกรณ์ Android 5.0
- ตรวจหาระบบไฟล์ที่ไม่ได้เข้ารหัสด้วย Flag
forceencrypt
/data
ไม่ได้เข้ารหัส แต่จำเป็นต้องเข้ารหัสเนื่องจากforceencrypt
กำหนดไว้ ถอด/data
- เริ่มเข้ารหัส
/data
vold.decrypt = "trigger_encryption"
ทริกเกอร์init.rc
ซึ่งทําให้vold
เข้ารหัส/data
โดยไม่ใช้รหัสผ่าน (ไม่ได้ตั้งค่าไว้เนื่องจากควรเป็นอุปกรณ์ใหม่) - ต่อเชื่อม tmpfs
vold
จะต่อเชื่อม tmpfs/data
(โดยใช้ตัวเลือก tmpfs จากro.crypto.tmpfs_options
) และตั้งค่าพร็อพเพอร์ตี้vold.encrypt_progress
เป็น 0vold
เตรียม tmpfs/data
เพื่อบูตระบบที่เข้ารหัสและตั้งค่าพร็อพเพอร์ตี้vold.decrypt
เป็นtrigger_restart_min_framework
- แสดงเฟรมเวิร์กเพื่อแสดงความคืบหน้า
เนื่องจากอุปกรณ์แทบจะไม่มีข้อมูลที่จะเข้ารหัส แถบความคืบหน้าจึงจะไม่ปรากฏบ่อยนักเนื่องจากการเข้ารหัสเกิดขึ้นอย่างรวดเร็ว ดูรายละเอียดเพิ่มเติมเกี่ยวกับ UI ความคืบหน้าได้ที่หัวข้อเข้ารหัสอุปกรณ์ที่มีอยู่
- เมื่อ
/data
ได้รับการเข้ารหัส ให้นำเฟรมเวิร์กออกvold
ตั้งค่าvold.decrypt
เป็นtrigger_default_encryption
ซึ่งจะเริ่มต้นบริการdefaultcrypto
(การดำเนินการนี้จะเริ่มต้นขั้นตอนด้านล่างสำหรับการต่อเชื่อมข้อมูลผู้ใช้ที่เข้ารหัสเริ่มต้น)trigger_default_encryption
ตรวจสอบประเภทการเข้ารหัสเพื่อดูว่า/data
ได้รับการเข้ารหัสโดยมีหรือไม่มีรหัสผ่าน เนื่องจากอุปกรณ์ Android 5.0 ได้รับการเข้ารหัสเมื่อบูตเครื่องครั้งแรก จึงไม่ควรมีการตั้งรหัสผ่าน เราจึงถอดรหัสและต่อเชื่อม/data
- Mount
/data
จากนั้น
init
จะต่อเชื่อม/data
ใน RAMDisk ของ tmpfs โดยใช้พารามิเตอร์ที่รับจากro.crypto.tmpfs_options
ซึ่งตั้งค่าไว้ในinit.rc
- Start Framework
vold
ตั้งค่าvold.decrypt
เป็นtrigger_restart_framework
ซึ่งจะดําเนินการบูตตามปกติต่อ
เข้ารหัสอุปกรณ์ที่มีอยู่
การดำเนินการนี้จะมีผลเมื่อคุณเข้ารหัสอุปกรณ์ Android K หรือเก่ากว่าที่ไม่ได้เข้ารหัสซึ่งย้ายข้อมูลไปยัง L แล้ว
กระบวนการนี้เริ่มต้นโดยผู้ใช้และเรียกว่า "การเข้ารหัสในตำแหน่ง" ในโค้ด เมื่อผู้ใช้เลือกเข้ารหัสอุปกรณ์ UI จะตรวจสอบว่าแบตเตอรี่ชาร์จเต็มแล้วและเสียบอะแดปเตอร์ AC ไว้เพื่อให้มีพลังงานเพียงพอที่จะเข้ารหัสให้เสร็จสิ้น
คำเตือน: หากแบตเตอรี่ของอุปกรณ์หมดและปิดไปก่อนการเข้ารหัสเสร็จสิ้น ข้อมูลไฟล์จะยังคงอยู่ในสถานะที่เข้ารหัสบางส่วน อุปกรณ์ต้องรีเซ็ตเป็นค่าเริ่มต้นและข้อมูลทั้งหมดจะหายไป
หากต้องการเปิดใช้การเข้ารหัสในตำแหน่งเดิม vold
จะเริ่มลูปเพื่ออ่านแต่ละภาคของอุปกรณ์บล็อกจริง แล้วเขียนลงในอุปกรณ์บล็อกการเข้ารหัส vold
จะตรวจสอบว่าเซกเตอร์มีการใช้งานอยู่หรือไม่ก่อนที่จะอ่านและเขียน ซึ่งทำให้การเข้ารหัสเร็วขึ้นมากในอุปกรณ์ใหม่ที่มีข้อมูลน้อยหรือไม่มีข้อมูล
สถานะของอุปกรณ์: ตั้งค่า ro.crypto.state = "unencrypted"
และเรียกใช้ทริกเกอร์ on nonencrypted
init
เพื่อบูตต่อ
- ตรวจสอบรหัสผ่าน
UI จะเรียก
vold
ด้วยคําสั่งcryptfs enablecrypto inplace
โดยที่passwd
คือรหัสผ่านหน้าจอล็อกของผู้ใช้ - นําเฟรมเวิร์กออก
vold
จะตรวจสอบข้อผิดพลาด แสดงผล -1 หากเข้ารหัสไม่ได้ และพิมพ์เหตุผลในบันทึก หากเข้ารหัสได้ ระบบจะตั้งค่าพร็อพเพอร์ตี้vold.decrypt
เป็นtrigger_shutdown_framework
ซึ่งทำให้init.rc
หยุดให้บริการในคลาสlate_start
และmain
- สร้างส่วนท้ายเกี่ยวกับคริปโต
- สร้างไฟล์เบรดครัมบ์
- รีบูต
- ตรวจหาไฟล์เบรดครัมบ์
- เริ่มเข้ารหัส
/data
vold
จะตั้งค่าการแมปการเข้ารหัส ซึ่งจะสร้างอุปกรณ์บล็อกการเข้ารหัสเสมือนจริงที่แมปกับอุปกรณ์บล็อกจริง แต่เข้ารหัสแต่ละภาคขณะเขียน และถอดรหัสแต่ละภาคขณะอ่านvold
จากนั้นจะสร้างและเขียนข้อมูลเมตาคริปโต - ขณะเข้ารหัส ให้ต่อเชื่อม tmpfs
vold
จะต่อเชื่อม tmpfs/data
(โดยใช้ตัวเลือก tmpfs จากro.crypto.tmpfs_options
) และตั้งค่าพร็อพเพอร์ตี้vold.encrypt_progress
เป็น 0vold
เตรียม tmpfs/data
สําหรับการบูตระบบที่เข้ารหัสและตั้งค่าพร็อพเพอร์ตี้vold.decrypt
เป็นtrigger_restart_min_framework
- แสดงเฟรมเวิร์กเพื่อแสดงความคืบหน้า
trigger_restart_min_framework
ทําให้init.rc
เริ่มบริการระดับmain
เมื่อเฟรมเวิร์กเห็นว่ามีการตั้งค่าvold.encrypt_progress
เป็น 0 ระบบจะแสดงแถบความคืบหน้า UI ซึ่งจะค้นหาพร็อพเพอร์ตี้นั้นทุกๆ 5 วินาทีและอัปเดตแถบความคืบหน้า ลูปการเข้ารหัสจะอัปเดตvold.encrypt_progress
ทุกครั้งที่เข้ารหัสอีกเปอร์เซ็นต์หนึ่งของพาร์ติชัน - เมื่อ
/data
ได้รับการเข้ารหัส ให้อัปเดตส่วนท้ายการเข้ารหัสเมื่อเข้ารหัส
/data
เรียบร้อยแล้วvold
จะล้าง FlagENCRYPTION_IN_PROGRESS
ในข้อมูลเมตาเมื่อปลดล็อกอุปกรณ์สำเร็จแล้ว ระบบจะใช้รหัสผ่านเพื่อเข้ารหัสคีย์หลักและอัปเดตส่วนท้ายการเข้ารหัส
หากการรีบูตไม่สำเร็จด้วยเหตุผลบางประการ
vold
จะตั้งค่าพร็อพเพอร์ตี้vold.encrypt_progress
เป็นerror_reboot_failed
และ UI ควรแสดงข้อความที่ขอให้ผู้ใช้กดปุ่มเพื่อรีบูต ซึ่งไม่ควรเกิดขึ้น
เริ่มอุปกรณ์ที่เข้ารหัสด้วยการเข้ารหัสเริ่มต้น
เหตุการณ์นี้จะเกิดขึ้นเมื่อคุณบูตอุปกรณ์ที่เข้ารหัสโดยไม่มีรหัสผ่าน เนื่องจากอุปกรณ์ Android 5.0 ได้รับการเข้ารหัสเมื่อบูตเครื่องครั้งแรก จึงไม่ควรมีการตั้งรหัสผ่าน และนี่คือสถานะการเข้ารหัสเริ่มต้น
- ตรวจหา
/data
ที่เข้ารหัสโดยไม่มีรหัสผ่านตรวจพบว่าอุปกรณ์ Android ได้รับการเข้ารหัสเนื่องจากไม่สามารถมา운ต์
/data
และตั้งค่า Flagencryptable
หรือforceencrypt
ไว้vold
ตั้งค่าvold.decrypt
เป็นtrigger_default_encryption
ซึ่งจะเริ่มต้นบริการdefaultcrypto
trigger_default_encryption
ตรวจสอบประเภทการเข้ารหัสเพื่อดูว่า/data
ได้รับการเข้ารหัสด้วยหรือไม่มีรหัสผ่าน - Decrypt /data
สร้างอุปกรณ์
dm-crypt
บนอุปกรณ์บล็อกเพื่อให้อุปกรณ์พร้อมใช้งาน - ต่อเชื่อม /data
vold
จากนั้นจะต่อเชื่อมพาร์ติชัน/data
จริงที่ถอดรหัสแล้ว และเตรียมพาร์ติชันใหม่ การตั้งค่าพร็อพเพอร์ตี้vold.post_fs_data_done
เป็น 0 แล้วตั้งค่าvold.decrypt
เป็นtrigger_post_fs_data
ซึ่งจะทำให้init.rc
เรียกใช้คำสั่งpost-fs-data
โดยสร้างไดเรกทอรีหรือลิงก์ที่จำเป็น แล้วตั้งค่าvold.post_fs_data_done
เป็น 1เมื่อ
vold
เห็น 1 ในพร็อพเพอร์ตี้นั้น ก็จะตั้งค่าพร็อพเพอร์ตี้vold.decrypt
เป็นtrigger_restart_framework.
ซึ่งทำให้init.rc
เริ่มบริการในคลาสmain
อีกครั้ง และเริ่มบริการในคลาสlate_start
เป็นครั้งแรกนับตั้งแต่การบูต - Start Framework
ตอนนี้เฟรมเวิร์กจะบูตบริการทั้งหมดโดยใช้
/data
ที่ถอดรหัสแล้ว และระบบก็พร้อมใช้งาน
เริ่มอุปกรณ์ที่เข้ารหัสโดยไม่มีการเข้ารหัสเริ่มต้น
สิ่งที่จะเกิดขึ้นเมื่อคุณบูตอุปกรณ์ที่เข้ารหัสซึ่งมีการตั้งรหัสผ่านไว้ รหัสผ่านของอุปกรณ์อาจเป็น PIN, รูปแบบ หรือรหัสผ่าน
- ตรวจหาอุปกรณ์ที่เข้ารหัสด้วยรหัสผ่าน
ตรวจพบว่าอุปกรณ์ Android ได้รับการเข้ารหัสเนื่องจาก Flag
ro.crypto.state = "encrypted"
vold
ตั้งค่าvold.decrypt
เป็นtrigger_restart_min_framework
เนื่องจาก/data
ได้รับการเข้ารหัสด้วยรหัสผ่าน - ต่อเชื่อม tmpfs
init
ตั้งค่าพร็อพเพอร์ตี้ 5 รายการเพื่อบันทึกตัวเลือกการต่อเชื่อมเริ่มต้นให้กับ/data
ด้วยพารามิเตอร์ที่ส่งมาจากinit.rc
vold
ใช้พร็อพเพอร์ตี้เหล่านี้เพื่อตั้งค่าการแมปคริปโตro.crypto.fs_type
ro.crypto.fs_real_blkdev
ro.crypto.fs_mnt_point
ro.crypto.fs_options
ro.crypto.fs_flags
(ตัวเลขฐาน 16 8 หลักของ ASCII ตามด้วย 0x)
- เริ่มเฟรมเวิร์กเพื่อแจ้งให้ป้อนรหัสผ่าน
เฟรมเวิร์กเริ่มต้นขึ้นและพบว่า
vold.decrypt
มีการตั้งค่าเป็นtrigger_restart_min_framework
ซึ่งจะบอกเฟรมเวิร์กว่ากำลังบูตในดิสก์ tmpfs/data
และต้องขอรหัสผ่านของผู้ใช้แต่ก่อนอื่น จะต้องตรวจสอบว่าดิสก์ได้รับการเข้ารหัสอย่างถูกต้อง โดยจะส่งคําสั่ง
cryptfs cryptocomplete
ไปยังvold
vold
จะแสดงผลเป็น 0 หากการเข้ารหัสเสร็จสมบูรณ์ -1 หากมีข้อผิดพลาดภายใน หรือ -2 หากการเข้ารหัสไม่เสร็จสมบูรณ์vold
จะระบุข้อมูลนี้โดยดูที่ธงCRYPTO_ENCRYPTION_IN_PROGRESS
ในข้อมูลเมตาของคริปโต หากตั้งค่าไว้ แสดงว่ากระบวนการเข้ารหัสถูกขัดจังหวะและไม่มีข้อมูลที่ใช้งานได้ในอุปกรณ์ หากvold
แสดงข้อผิดพลาด UI ควรแสดงข้อความให้ผู้ใช้รีบูตและรีเซ็ตอุปกรณ์เป็นค่าเริ่มต้น รวมถึงแสดงปุ่มให้ผู้ใช้กดเพื่อดำเนินการดังกล่าว - ถอดรหัสข้อมูลด้วยรหัสผ่าน
เมื่อ
cryptfs cryptocomplete
ดำเนินการเสร็จสมบูรณ์แล้ว เฟรมเวิร์กจะแสดง UI ที่ขอรหัสผ่านของดิสก์ UI จะตรวจสอบรหัสผ่านโดยส่งคําสั่งcryptfs checkpw
ไปยังvold
หากรหัสผ่านถูกต้อง (ซึ่งพิจารณาจากการต่อเชื่อม/data
ที่ถอดรหัสแล้วในตำแหน่งชั่วคราวและถอดออกเรียบร้อยแล้ว)vold
จะบันทึกชื่ออุปกรณ์บล็อกที่ถอดรหัสแล้วในพร็อพเพอร์ตี้ro.crypto.fs_crypto_blkdev
และแสดงสถานะ 0 ไปยัง UI หากรหัสผ่านไม่ถูกต้อง ระบบจะแสดงผล -1 ใน UI - เฟรมเวิร์กหยุด
UI จะแสดงกราฟิกการบูตคริปโต จากนั้นเรียกใช้
vold
ด้วยคำสั่งcryptfs restart
vold
ตั้งค่าพร็อพเพอร์ตี้vold.decrypt
เป็นtrigger_reset_main
ซึ่งทําให้init.rc
ทําclass_reset main
ซึ่งจะหยุดบริการทั้งหมดในคลาสหลัก ซึ่งจะช่วยให้ยกเลิกการต่อเชื่อม tmpfs/data
ได้ - Mount
/data
vold
จากนั้นจะต่อเชื่อมพาร์ติชัน/data
จริงที่ถอดรหัสแล้ว และเตรียมพาร์ติชันใหม่ (ซึ่งอาจไม่เคยเตรียมไว้หากมีการเข้ารหัสด้วยตัวเลือกการลบ ซึ่งไม่รองรับในรุ่นแรก) ซึ่งจะตั้งค่าพร็อพเพอร์ตี้vold.post_fs_data_done
เป็น 0 แล้วตั้งค่าvold.decrypt
เป็นtrigger_post_fs_data
ซึ่งจะทำให้init.rc
เรียกใช้คำสั่งpost-fs-data
โดยสร้างไดเรกทอรีหรือลิงก์ที่จำเป็น แล้วตั้งค่าvold.post_fs_data_done
เป็น 1 เมื่อvold
เห็น 1 ในพร็อพเพอร์ตี้นั้น ก็จะตั้งค่าพร็อพเพอร์ตี้vold.decrypt
เป็นtrigger_restart_framework
ซึ่งทำให้init.rc
เริ่มบริการในชั้นเรียนmain
อีกครั้ง และเริ่มบริการในชั้นเรียนlate_start
เป็นครั้งแรกนับตั้งแต่การบูต - เริ่มใช้งานเฟรมเวิร์กแบบสมบูรณ์
ตอนนี้เฟรมเวิร์กจะบูตบริการทั้งหมดโดยใช้
/data
ระบบไฟล์ที่ถอดรหัสแล้ว และระบบก็พร้อมใช้งาน
ไม่สำเร็จ
อุปกรณ์ที่ถอดรหัสไม่สำเร็จอาจมีปัญหาอยู่ 2-3 อย่าง อุปกรณ์จะเริ่มต้นด้วยชุดขั้นตอนปกติในการบูต ดังนี้
- ตรวจหาอุปกรณ์ที่เข้ารหัสด้วยรหัสผ่าน
- ต่อเชื่อม tmpfs
- เริ่มเฟรมเวิร์กเพื่อแจ้งให้ป้อนรหัสผ่าน
แต่หลังจากเปิดเฟรมเวิร์กแล้ว อุปกรณ์อาจพบข้อผิดพลาดบางอย่าง ดังนี้
- รหัสผ่านตรงกันแต่ถอดรหัสข้อมูลไม่ได้
- ผู้ใช้ป้อนรหัสผ่านไม่ถูกต้อง 30 ครั้ง
หากข้อผิดพลาดเหล่านี้ไม่ได้รับการแก้ไข ให้แจ้งให้ผู้ใช้ล้างข้อมูลเป็นค่าเริ่มต้น
หาก vold
ตรวจพบข้อผิดพลาดระหว่างกระบวนการเข้ารหัส และหากยังไม่มีการทำลายข้อมูลและเฟรมเวิร์กทำงานอยู่ vold
จะตั้งค่าพร็อพเพอร์ตี้ vold.encrypt_progress
เป็น error_not_encrypted
UI จะแจ้งให้ผู้ใช้รีบูตและแจ้งให้ทราบว่ากระบวนการเข้ารหัสไม่เคยเริ่มต้น หากข้อผิดพลาดเกิดขึ้นหลังจากระบบได้รื้อเฟรมเวิร์กออกแล้ว แต่ก่อน UI แถบความคืบหน้าจะปรากฏขึ้น vold
จะรีบูตระบบ หากรีบูตไม่สำเร็จ ระบบจะตั้งค่า vold.encrypt_progress
เป็น error_shutting_down
และแสดงผล -1 แต่จะไม่มีสิ่งใดที่จะจับข้อผิดพลาดได้ ซึ่งไม่ควรจะเกิดขึ้น
หาก vold
ตรวจพบข้อผิดพลาดระหว่างกระบวนการเข้ารหัส ระบบจะตั้งค่า vold.encrypt_progress
เป็น error_partially_encrypted
และแสดงผล -1 จากนั้น UI ควรแสดงข้อความว่าการเข้ารหัสไม่สำเร็จ และมีปุ่มให้ผู้ใช้รีเซ็ตอุปกรณ์เป็นค่าเริ่มต้น
จัดเก็บคีย์ที่เข้ารหัส
ระบบจะจัดเก็บคีย์ที่เข้ารหัสไว้ในข้อมูลเมตาการเข้ารหัส แบ็กกิ้งฮาร์ดแวร์จะติดตั้งใช้งานโดยใช้ความสามารถในการลงชื่อของสภาพแวดล้อมการดำเนินการที่เชื่อถือได้ (TEE) ก่อนหน้านี้ เราเข้ารหัสคีย์หลักด้วยคีย์ที่สร้างขึ้นโดยใช้ scrypt กับรหัสผ่านของผู้ใช้และเกลือที่จัดเก็บไว้ เราได้ขยายอัลกอริทึมนี้ด้วยการเซ็นชื่อคีย์ที่ได้โดยใช้คีย์ TEE ที่เก็บไว้เพื่อให้คีย์มีความยืดหยุ่นต่อการโจมตีนอกอุปกรณ์ จากนั้นระบบจะเปลี่ยนลายเซ็นที่ได้เป็นคีย์ที่มีความยาวที่เหมาะสมโดยใช้ scrypt อีก 1 ครั้ง จากนั้นระบบจะใช้คีย์นี้เพื่อเข้ารหัสและถอดรหัสคีย์หลัก วิธีจัดเก็บคีย์นี้
- สร้างคีย์การเข้ารหัสดิสก์ (DEK) 16 ไบต์และเกลือ 16 ไบต์แบบสุ่ม
- ใช้ Scrypt กับรหัสผ่านของผู้ใช้และ Salt เพื่อสร้างคีย์กลาง 32 ไบต์ 1 (IK1)
- เพิ่มค่า 0 ไบต์ลงใน IK1 จนมีขนาดเท่ากับคีย์ส่วนตัวที่เชื่อมโยงกับฮาร์ดแวร์ (HBK) กล่าวโดยละเอียดคือ เราจะเพิ่มค่าดังนี้ 00 || IK1 || 00..00; ไบต์ 0 1 ไบต์, IK1 32 ไบต์, 223 ไบต์ 0
- ลงชื่อ IK1 ที่เพิ่มค่าไว้ด้วย HBK เพื่อสร้าง IK2 ขนาด 256 ไบต์
- ใช้ Scrypt กับ IK2 และ Salt (Salt เดียวกับขั้นตอนที่ 2) เพื่อสร้าง IK3 ขนาด 32 ไบต์
- ใช้ 16 ไบต์แรกของ IK3 เป็น KEK และ 16 ไบต์สุดท้ายเป็น IV
- เข้ารหัส DEK ด้วย AES_CBC, คีย์ KEK และเวกเตอร์การเริ่มต้น IV
เปลี่ยนรหัสผ่าน
เมื่อผู้ใช้เลือกเปลี่ยนหรือนำรหัสผ่านออกในการตั้งค่า UI จะส่งคำสั่ง cryptfs changepw
ไปยัง vold
และ vold
จะเข้ารหัสคีย์หลักของดิสก์อีกครั้งด้วยรหัสผ่านใหม่
พร็อพเพอร์ตี้การเข้ารหัส
vold
และ init
สื่อสารกันโดยการตั้งค่าพร็อพเพอร์ตี้ ต่อไปนี้คือรายการพร็อพเพอร์ตี้ที่ใช้ได้สำหรับการเข้ารหัส
พร็อพเพอร์ตี้ Vold
พร็อพเพอร์ตี้ | คำอธิบาย |
---|---|
vold.decrypt trigger_encryption |
เข้ารหัสไดรฟ์โดยไม่มีรหัสผ่าน |
vold.decrypt trigger_default_encryption |
ตรวจสอบไดรฟ์เพื่อดูว่ามีการเข้ารหัสโดยไม่มีรหัสผ่านหรือไม่
หากเป็นเช่นนั้น ให้ถอดรหัสและต่อเชื่อม มิเช่นนั้น ให้ตั้งค่า vold.decrypt เป็น trigger_restart_min_framework |
vold.decrypt trigger_reset_main |
ตั้งค่าโดย vold เพื่อปิด UI ที่ขอรหัสผ่านของดิสก์ |
vold.decrypt trigger_post_fs_data |
ตั้งค่าโดย vold เพื่อเตรียม /data ด้วยไดเรกทอรีที่จำเป็นและอื่นๆ |
vold.decrypt trigger_restart_framework |
ตั้งค่าโดย vold เพื่อเริ่มเฟรมเวิร์กจริงและบริการทั้งหมด |
vold.decrypt trigger_shutdown_framework |
ตั้งค่าโดย vold เพื่อปิดเฟรมเวิร์กทั้งหมดเพื่อเริ่มการเข้ารหัส |
vold.decrypt trigger_restart_min_framework |
ตั้งค่าโดย vold เพื่อเริ่ม UI แถบความคืบหน้าสำหรับการเข้ารหัสหรือแสดงข้อความแจ้งให้ป้อนรหัสผ่าน โดยขึ้นอยู่กับค่าของ ro.crypto.state |
vold.encrypt_progress |
เมื่อเฟรมเวิร์กเริ่มต้นขึ้น ระบบจะเข้าสู่โหมด UI แถบความคืบหน้าหากตั้งค่าพร็อพเพอร์ตี้นี้ไว้ |
vold.encrypt_progress 0 to 100 |
UI แถบความคืบหน้าควรแสดงค่าเปอร์เซ็นต์ที่ตั้งไว้ |
vold.encrypt_progress error_partially_encrypted |
UI แถบความคืบหน้าควรแสดงข้อความว่าการเข้ารหัสไม่สำเร็จ และตัวเลือกให้ผู้ใช้รีเซ็ตอุปกรณ์เป็นค่าเริ่มต้น |
vold.encrypt_progress error_reboot_failed |
UI แถบความคืบหน้าควรแสดงข้อความว่า "เข้ารหัสเสร็จสมบูรณ์" และมีปุ่มให้ผู้ใช้รีบูตอุปกรณ์ ข้อผิดพลาดนี้ไม่ควรเกิดขึ้น |
vold.encrypt_progress error_not_encrypted |
UI แถบความคืบหน้าควรแสดงข้อความว่าเกิดข้อผิดพลาดขึ้น ไม่มีข้อมูลได้รับการเข้ารหัสหรือสูญหาย และแสดงปุ่มให้ผู้ใช้รีบูตระบบ |
vold.encrypt_progress error_shutting_down |
UI แถบความคืบหน้าไม่ทำงาน จึงไม่แน่ใจว่าใครเป็นผู้ตอบกลับข้อผิดพลาดนี้ และไม่ควรเกิดขึ้น |
vold.post_fs_data_done 0 |
ตั้งค่าโดย vold ก่อนที่จะตั้งค่า vold.decrypt เป็น trigger_post_fs_data |
vold.post_fs_data_done 1 |
ตั้งค่าโดย init.rc หรือ
init.rc ทันทีหลังจากทำภารกิจ post-fs-data เสร็จ |
พร็อพเพอร์ตี้ init
พร็อพเพอร์ตี้ | คำอธิบาย |
---|---|
ro.crypto.fs_crypto_blkdev |
ตั้งค่าโดยvold คําสั่ง checkpw สําหรับใช้ภายหลังโดยvold คําสั่ง restart |
ro.crypto.state unencrypted |
ตั้งค่าโดย init เพื่อระบุว่าระบบนี้ทำงานด้วย /data ro.crypto.state encrypted ที่ไม่ได้เข้ารหัส ตั้งค่าโดย init เพื่อพูดว่าระบบนี้ทำงานด้วย /data ที่เข้ารหัส |
|
init จะตั้งค่าพร็อพเพอร์ตี้ทั้ง 5 รายการนี้เมื่อพยายามต่อเชื่อม /data ด้วยพารามิเตอร์ที่ส่งมาจาก init.rc vold ใช้ข้อมูลเหล่านี้เพื่อตั้งค่าการแมปคริปโต |
ro.crypto.tmpfs_options |
ตั้งค่าโดย init.rc ด้วยตัวเลือกที่ init ควรใช้เมื่อทำการต่อเชื่อมระบบไฟล์ tmpfs /data |
init actions
on post-fs-data on nonencrypted on property:vold.decrypt=trigger_reset_main on property:vold.decrypt=trigger_post_fs_data on property:vold.decrypt=trigger_restart_min_framework on property:vold.decrypt=trigger_restart_framework on property:vold.decrypt=trigger_shutdown_framework on property:vold.decrypt=trigger_encryption on property:vold.decrypt=trigger_default_encryption