การเข้ารหัสทั้งดิสก์คือกระบวนการเข้ารหัสข้อมูลผู้ใช้ทั้งหมดบนอุปกรณ์ Android โดยใช้คีย์เข้ารหัส เมื่อเข้ารหัสอุปกรณ์แล้ว ข้อมูลทั้งหมดที่สร้างโดยผู้ใช้จะถูกเข้ารหัสโดยอัตโนมัติก่อนที่จะส่งไปยังดิสก์ และการอ่านข้อมูลทั้งหมดจะถอดรหัสข้อมูลโดยอัตโนมัติก่อนที่จะส่งคืนไปยังกระบวนการเรียก
การเข้ารหัสทั้งดิสก์ถูกนำมาใช้กับ Android ในเวอร์ชัน 4.4 แต่ Android 5.0 ได้แนะนำคุณลักษณะใหม่เหล่านี้:
- สร้างการเข้ารหัสที่รวดเร็ว ซึ่งจะเข้ารหัสเฉพาะบล็อกที่ใช้แล้วบนพาร์ติชันข้อมูลเพื่อหลีกเลี่ยงการบูตครั้งแรกที่ใช้เวลานาน ขณะนี้ระบบไฟล์ ext4 และ f2fs เท่านั้นที่รองรับการเข้ารหัสที่รวดเร็ว
- เพิ่ม ธง
forceencrypt
fstab เพื่อเข้ารหัสในการบูตครั้งแรก - เพิ่มการรองรับรูปแบบและการเข้ารหัสโดยไม่ต้องใช้รหัสผ่าน
- เพิ่มที่เก็บข้อมูลคีย์เข้ารหัสที่สนับสนุนฮาร์ดแวร์โดยใช้ความสามารถในการลงนามของ Trusted Execution Environment (TEE) (เช่นใน TrustZone) โปรดดูรายละเอียดเพิ่มเติมใน การจัดเก็บคีย์ที่เข้ารหัส
ข้อควรระวัง: อุปกรณ์ที่อัปเกรดเป็น Android 5.0 แล้วเข้ารหัสแล้วอาจกลับสู่สถานะที่ไม่ได้เข้ารหัสโดยการรีเซ็ตข้อมูลเป็นค่าเริ่มต้น อุปกรณ์ Android 5.0 ใหม่ที่เข้ารหัสเมื่อบู๊ตครั้งแรกจะไม่สามารถกลับสู่สถานะที่ไม่ได้เข้ารหัสได้
วิธีการทำงานของการเข้ารหัสทั้งดิสก์ของ Android
การเข้ารหัสทั้งดิสก์ของ Android ใช้ dm-crypt
ซึ่งเป็นคุณลักษณะเคอร์เนลที่ทำงานที่ชั้นอุปกรณ์บล็อก ด้วยเหตุนี้ การเข้ารหัสจึงทำงานร่วมกับ Embedded MultiMediaCard ( eMMC) และอุปกรณ์แฟลชที่คล้ายกันซึ่งนำเสนอตัวเองในเคอร์เนลเป็นอุปกรณ์บล็อก ไม่สามารถเข้ารหัสด้วย YAFFS ซึ่งพูดโดยตรงกับชิปแฟลช NAND ดิบ
อัลกอริธึมการเข้ารหัสคือ 128 Advanced Encryption Standard (AES) พร้อมด้วย cipher-block chaining (CBC) และ ESSIV:SHA256 มาสเตอร์คีย์ถูกเข้ารหัสด้วย AES 128 บิตผ่านการเรียกไปยังไลบรารี OpenSSL คุณต้องใช้ 128 บิตขึ้นไปสำหรับคีย์ (โดยที่ 256 เป็นทางเลือก)
หมายเหตุ: OEM สามารถใช้ 128 บิตหรือสูงกว่าเพื่อเข้ารหัสมาสเตอร์คีย์ได้
ในการเปิดตัว Android 5.0 มีสถานะการเข้ารหัสสี่ประเภท:
- ค่าเริ่มต้น
- เข็มหมุด
- รหัสผ่าน
- ลวดลาย
เมื่อบู๊ตครั้งแรก อุปกรณ์จะสร้างมาสเตอร์คีย์ 128 บิตที่สร้างขึ้นแบบสุ่ม จากนั้นแฮชด้วยรหัสผ่านเริ่มต้นและเกลือที่เก็บไว้ รหัสผ่านเริ่มต้นคือ: "default_password" อย่างไรก็ตาม แฮชผลลัพธ์ยังถูกเซ็นผ่าน TEE (เช่น TrustZone) ซึ่งใช้แฮชของลายเซ็นเพื่อเข้ารหัสคีย์หลัก
คุณสามารถค้นหารหัสผ่านเริ่มต้นที่กำหนดไว้ในไฟล์ cryptfs.cpp ของ Android Open Source Project
เมื่อผู้ใช้ตั้งค่า PIN/รหัสผ่าน หรือรหัสผ่านบนอุปกรณ์ เฉพาะคีย์ 128 บิตเท่านั้นที่จะถูกเข้ารหัสและจัดเก็บใหม่ (เช่น การเปลี่ยนแปลง PIN/รหัสผ่าน/รูปแบบของผู้ใช้จะไม่ทำให้เกิดการเข้ารหัสซ้ำของข้อมูลผู้ใช้) โปรดทราบว่า อุปกรณ์ที่มีการจัดการ อาจอยู่ภายใต้ข้อจำกัดของ PIN รูปแบบ หรือรหัสผ่าน
การเข้ารหัสถูกจัดการโดย init
และ vold
init
เรียก vold
และ vold ตั้งค่าคุณสมบัติเพื่อทริกเกอร์เหตุการณ์ใน init ส่วนอื่นๆ ของระบบยังดูที่คุณสมบัติเพื่อดำเนินการต่างๆ เช่น สถานะรายงาน ขอรหัสผ่าน หรือแจ้งให้รีเซ็ตเป็นค่าเริ่มต้นจากโรงงานในกรณีที่เกิดข้อผิดพลาดร้ายแรง ในการเรียกใช้คุณสมบัติการเข้ารหัสใน vold
ระบบจะใช้เครื่องมือบรรทัดคำสั่ง vdc
คำสั่ง cryptfs
: checkpw
, restart
, enablecrypto
, changepw
, cryptocomplete
, verifypw
, setfield
, getfield
, mountdefaultencrypted
, getpwtype
, getpw
และ clearpw
ในการเข้ารหัส ถอดรหัส หรือล้าง /data
data จะต้องไม่เมาต์ /data
อย่างไรก็ตาม เพื่อแสดงส่วนต่อประสานผู้ใช้ (UI) กรอบงานต้องเริ่มทำงานและกรอบงานต้องการ /data
เพื่อเรียกใช้ เพื่อแก้ไขปริศนานี้ ระบบไฟล์ชั่วคราวจะถูกติดตั้งบน /data
ซึ่งช่วยให้ Android สามารถขอรหัสผ่าน แสดงความคืบหน้า หรือแนะนำการล้างข้อมูลได้ตามต้องการ มีข้อจำกัดว่าในการเปลี่ยนจากระบบไฟล์ชั่วคราวเป็นระบบไฟล์ /data
จริง ระบบต้องหยุดทุกกระบวนการที่มีไฟล์เปิดอยู่บนระบบไฟล์ชั่วคราว และรีสตาร์ทกระบวนการเหล่านั้นบนระบบไฟล์ /data
จริง ในการทำเช่นนี้ บริการทั้งหมดต้องอยู่ในกลุ่มใดกลุ่มหนึ่งจากสามกลุ่ม: core
, main
และ late_start
-
core
: อย่าปิดเครื่องหลังจากเริ่มต้น -
main
: ปิดเครื่องแล้วรีสตาร์ทหลังจากป้อนรหัสผ่านของดิสก์ -
late_start
: ไม่เริ่มจนกว่า/data
จะถูกถอดรหัสและติดตั้ง
หากต้องการทริกเกอร์การกระทำเหล่านี้ คุณสมบัติ vold.decrypt
จะถูกตั้งค่าเป็น สตริงต่างๆ หากต้องการหยุดและเริ่มบริการใหม่ คำสั่ง init
คือ:
-
class_reset
: หยุดบริการ แต่อนุญาตให้รีสตาร์ทด้วย class_start -
class_start
: เริ่มบริการใหม่ -
class_stop
: หยุดบริการและเพิ่มแฟล็กSVC_DISABLED
บริการที่หยุดทำงานไม่ตอบสนองต่อclass_start
กระแส
มีสี่โฟลว์สำหรับอุปกรณ์ที่เข้ารหัส อุปกรณ์ได้รับการเข้ารหัสเพียงครั้งเดียวจากนั้นทำตามขั้นตอนการบูตปกติ
- เข้ารหัสอุปกรณ์ที่ไม่ได้เข้ารหัสก่อนหน้านี้:
- เข้ารหัสอุปกรณ์ใหม่ด้วย
forceencrypt
: การเข้ารหัสบังคับเมื่อบู๊ตครั้งแรก (เริ่มต้นใน Android L) - เข้ารหัสอุปกรณ์ที่มีอยู่: การเข้ารหัสที่เริ่มต้นโดยผู้ใช้ (Android K และรุ่นก่อนหน้า)
- เข้ารหัสอุปกรณ์ใหม่ด้วย
- บูตอุปกรณ์ที่เข้ารหัส:
- การเริ่มอุปกรณ์ที่เข้ารหัสโดยไม่มีรหัสผ่าน: การบูตอุปกรณ์ที่เข้ารหัสซึ่งไม่ได้ตั้งรหัสผ่าน (เกี่ยวข้องกับอุปกรณ์ที่ใช้ Android 5.0 และใหม่กว่า)
- การเริ่มอุปกรณ์ที่เข้ารหัสด้วยรหัสผ่าน: การบูตอุปกรณ์ที่เข้ารหัสซึ่งมีรหัสผ่านที่ตั้งไว้
นอกจากโฟลว์เหล่านี้แล้ว อุปกรณ์ยังสามารถเข้ารหัสล้มเหลวได้ /data
แต่ละโฟลว์มีคำอธิบายโดยละเอียดด้านล่าง
เข้ารหัสอุปกรณ์ใหม่ด้วยการบังคับเข้ารหัส
นี่เป็นการบู๊ตครั้งแรกตามปกติสำหรับอุปกรณ์ Android 5.0
- ตรวจหาระบบไฟล์ที่ไม่ได้เข้ารหัสด้วยการตั้งค่าสถานะ
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
- เมานต์
/data
จากนั้น
init
จะเมานต์/data
บน tmpfs RAMDisk โดยใช้พารามิเตอร์ที่รับมาจากro.crypto.tmpfs_options
ซึ่งตั้งค่าไว้ในinit.rc
- เริ่มกรอบ
vold
ตั้งค่าvold.decrypt
เป็นtrigger_restart_framework
ซึ่งจะดำเนินต่อตามกระบวนการบูตตามปกติ
เข้ารหัสอุปกรณ์ที่มีอยู่
นี่คือสิ่งที่เกิดขึ้นเมื่อคุณเข้ารหัส Android K หรืออุปกรณ์รุ่นก่อนหน้าที่ไม่ได้เข้ารหัสซึ่งถูกย้ายไปยัง L
กระบวนการนี้เริ่มต้นโดยผู้ใช้และเรียกว่า "inplace encryption" ในรหัส เมื่อผู้ใช้เลือกที่จะเข้ารหัสอุปกรณ์ UI จะตรวจสอบให้แน่ใจว่าแบตเตอรี่ชาร์จเต็มแล้วและเสียบอะแดปเตอร์ AC เพื่อให้มีพลังงานเพียงพอที่จะเสร็จสิ้นกระบวนการเข้ารหัส
คำเตือน: หากอุปกรณ์ไฟฟ้าหมดและปิดก่อนที่จะเข้ารหัสเสร็จ ข้อมูลไฟล์จะอยู่ในสถานะเข้ารหัสบางส่วน ต้องรีเซ็ตอุปกรณ์เป็นค่าเริ่มต้นและข้อมูลทั้งหมดจะสูญหาย
ในการเปิดใช้งานการเข้ารหัสแบบแทนที่ vold
จะเริ่มวนรอบเพื่ออ่านแต่ละส่วนของอุปกรณ์บล็อกจริง จากนั้นจึงเขียนไปยังอุปกรณ์บล็อกการเข้ารหัสลับ vold
ตรวจสอบเพื่อดูว่ามีการใช้เซกเตอร์หรือไม่ก่อนที่จะอ่านและเขียน ซึ่งทำให้การเข้ารหัสเร็วขึ้นมากบนอุปกรณ์ใหม่ที่มีข้อมูลเพียงเล็กน้อยหรือไม่มีเลย
สถานะของอุปกรณ์ : ตั้งค่า ro.crypto.state = "unencrypted"
และเรียกใช้ทริกเกอร์ init
on nonencrypted
เพื่อดำเนินการบูทต่อไป
- ตรวจสอบรหัสผ่าน
UI เรียก
vold
ด้วยคำสั่งcryptfs enablecrypto inplace
โดยที่passwd
เป็นรหัสผ่านล็อคหน้าจอของผู้ใช้ - ถอดกรอบ
vold
ตรวจสอบข้อผิดพลาด ส่งกลับ -1 หากไม่สามารถเข้ารหัส และพิมพ์เหตุผลในบันทึก หากสามารถเข้ารหัสได้ จะตั้งค่าคุณสมบัติvold.decrypt
เป็นtrigger_shutdown_framework
สิ่งนี้ทำให้init.rc
หยุดบริการในคลาสlate_start
และmain
- สร้างส่วนท้ายของการเข้ารหัสลับ
- สร้างไฟล์เบรดครัมบ์
- รีบูต
- ตรวจหาไฟล์เบรดครัมบ์
- เริ่มการเข้ารหัส
/data
จากนั้น
vold
จะตั้งค่าการแมป crypto ซึ่งสร้างอุปกรณ์บล็อก crypto เสมือนจริงที่แมปบนอุปกรณ์บล็อกจริง แต่เข้ารหัสแต่ละเซกเตอร์ตามที่เขียน และถอดรหัสแต่ละเซกเตอร์ตามที่อ่าน จากนั้น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 ของแถบความคืบหน้า ซึ่งจะสอบถามคุณสมบัตินั้นทุก ๆ ห้าวินาทีและอัปเดตแถบความคืบหน้า ลูปการเข้ารหัสจะอัปเดตvold.encrypt_progress
ทุกครั้งที่เข้ารหัสพาร์ติชันอีกเปอร์เซ็นต์ - เมื่อ
/data
ถูกเข้ารหัส ให้อัปเดตส่วนท้ายของ cryptoเมื่อเข้ารหัส
/data
สำเร็จvold
จะล้างแฟล็กENCRYPTION_IN_PROGRESS
ในข้อมูลเมตาเมื่อปลดล็อคอุปกรณ์สำเร็จ รหัสผ่านจะถูกใช้เพื่อเข้ารหัสมาสเตอร์คีย์และส่วนท้ายของการเข้ารหัสลับจะได้รับการอัปเดต
หากการรีบูตล้มเหลวด้วยเหตุผลบางประการ
vold
จะตั้งค่าคุณสมบัติvold.encrypt_progress
เป็นerror_reboot_failed
และ UI ควรแสดงข้อความที่ขอให้ผู้ใช้กดปุ่มเพื่อรีบูต สิ่งนี้ไม่คาดว่าจะเกิดขึ้น
การเริ่มต้นอุปกรณ์ที่เข้ารหัสด้วยการเข้ารหัสเริ่มต้น
นี่คือสิ่งที่เกิดขึ้นเมื่อคุณบู๊ตอุปกรณ์ที่เข้ารหัสโดยไม่มีรหัสผ่าน เนื่องจากอุปกรณ์ Android 5.0 ได้รับการเข้ารหัสเมื่อบู๊ตครั้งแรก จึงไม่ควรตั้งรหัสผ่าน ดังนั้นจึงเป็นสถานะ การเข้ารหัสเริ่มต้น
- ตรวจหาการเข้ารหัส
/data
โดยไม่มีรหัสผ่านตรวจหาว่าอุปกรณ์ Android ได้รับการเข้ารหัสเนื่องจาก
/data
ไม่สามารถเมานต์ได้ และมีการตั้งค่าแฟล็กencryptable
หรือforceencrypt
อย่างใดอย่างหนึ่งvold
ตั้งค่าvold.decrypt
เป็นtrigger_default_encryption
ซึ่งเริ่มบริการdefaultcrypto
trigger_default_encryption
ตรวจสอบประเภทการเข้ารหัสเพื่อดูว่า/data
ถูกเข้ารหัสด้วยหรือไม่มีรหัสผ่าน - ถอดรหัส/ข้อมูล
สร้างอุปกรณ์
dm-crypt
เหนืออุปกรณ์บล็อกเพื่อให้อุปกรณ์พร้อมใช้งาน - เมานต์ / ข้อมูล
จากนั้น
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
และระบบพร้อมใช้งานแล้ว
การเริ่มต้นอุปกรณ์ที่เข้ารหัสโดยไม่มีการเข้ารหัสเริ่มต้น
นี่คือสิ่งที่เกิดขึ้นเมื่อคุณบู๊ตอุปกรณ์ที่เข้ารหัสซึ่งมีรหัสผ่านที่ตั้งไว้ รหัสผ่านของอุปกรณ์อาจเป็นพิน รูปแบบ หรือรหัสผ่านก็ได้
- ตรวจหาอุปกรณ์ที่เข้ารหัสด้วยรหัสผ่าน
ตรวจพบว่าอุปกรณ์ Android ได้รับการเข้ารหัสเนื่องจากการตั้งค่าสถานะ
ro.crypto.state = "encrypted"
vold
ตั้งค่าvold.decrypt
เป็นtrigger_restart_min_framework
เนื่องจาก/data
ถูกเข้ารหัสด้วยรหัสผ่าน - เมานต์ tmpfs
init
ตั้งค่าห้าคุณสมบัติเพื่อบันทึกตัวเลือกการเมาต์เริ่มต้นที่กำหนดสำหรับ/data
พร้อมพารามิเตอร์ที่ส่งผ่านจากinit.rc
vold
ใช้คุณสมบัติเหล่านี้เพื่อตั้งค่าการแมป crypto:-
ro.crypto.fs_type
-
ro.crypto.fs_real_blkdev
-
ro.crypto.fs_mnt_point
-
ro.crypto.fs_options
-
ro.crypto.fs_flags
(เลขฐานสิบหก ASCII 8 หลักนำหน้าด้วย 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 สร้างกราฟิกสำหรับบูต crypto จากนั้นเรียก
vold
ด้วยคำสั่งcryptfs restart
vold
ตั้งค่าคุณสมบัติvold.decrypt
เป็นtrigger_reset_main
ซึ่งทำให้init.rc
ทำclass_reset main
สิ่งนี้จะหยุดบริการทั้งหมดในคลาสหลัก ซึ่งอนุญาตให้ยกเลิกการต่อเชื่อม tmpfs/data
- เมานต์
/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
ที่ถอดรหัส และระบบพร้อมใช้งานแล้ว
ความล้มเหลว
อุปกรณ์ที่ถอดรหัสไม่สำเร็จอาจทำงานผิดปกติด้วยเหตุผลบางประการ อุปกรณ์เริ่มต้นด้วยชุดขั้นตอนปกติในการบู๊ต:
- ตรวจหาอุปกรณ์ที่เข้ารหัสด้วยรหัสผ่าน
- เมานต์ 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 ควรแสดงข้อความแจ้งว่าการเข้ารหัสล้มเหลว และจัดเตรียมปุ่มให้ผู้ใช้รีเซ็ตอุปกรณ์เป็นค่าเริ่มต้น
การจัดเก็บคีย์ที่เข้ารหัส
คีย์ที่เข้ารหัสจะถูกจัดเก็บไว้ในข้อมูลเมตาของการเข้ารหัสลับ การสำรองฮาร์ดแวร์ถูกนำมาใช้โดยใช้ความสามารถในการลงนามของ Trusted Execution Environment (TEE) ก่อนหน้านี้ เราเข้ารหัสมาสเตอร์คีย์ด้วยคีย์ที่สร้างขึ้นโดยการใช้ scrypt กับรหัสผ่านของผู้ใช้และเกลือที่เก็บไว้ เพื่อทำให้คีย์สามารถต้านทานการโจมตีนอกกรอบได้ เราจึงขยายอัลกอริทึมนี้โดยการเซ็นชื่อคีย์ผลลัพธ์ด้วยคีย์ TEE ที่เก็บไว้ ลายเซ็นที่เป็นผลลัพธ์จะเปลี่ยนเป็นคีย์ความยาวที่เหมาะสมโดยการใช้ scrypt อีกหนึ่งโปรแกรม คีย์นี้ใช้เพื่อเข้ารหัสและถอดรหัสคีย์หลัก ในการจัดเก็บคีย์นี้:
- สร้างคีย์เข้ารหัสดิสก์ (DEK) แบบสุ่ม 16 ไบต์และเกลือ 16 ไบต์
- ใช้ scrypt กับรหัสผ่านผู้ใช้และเกลือเพื่อสร้างคีย์กลาง 32 ไบต์ 1 (IK1)
- Pad IK1 ที่มีศูนย์ไบต์เป็นขนาดของคีย์ส่วนตัวที่เชื่อมต่อกับฮาร์ดแวร์ (HBK) โดยเฉพาะอย่างยิ่ง เราใส่เป็น: 00 || IK1 || 00..00; หนึ่งศูนย์ไบต์, 32 IK1 ไบต์, 223 ศูนย์ไบต์
- เซ็นชื่อ IK1 ที่บุนวมด้วย HBK เพื่อสร้าง IK2 ขนาด 256 ไบต์
- ใช้ scrypt กับ IK2 และเกลือ (เกลือเดียวกับขั้นตอนที่ 2) เพื่อสร้าง IK3 ขนาด 32 ไบต์
- ใช้ 16 ไบต์แรกของ IK3 เป็น KEK และ 16 ไบต์สุดท้ายเป็น IV
- เข้ารหัส DEK ด้วย AES_CBC ด้วยคีย์ KEK และการเริ่มต้นเวกเตอร์ IV
การเปลี่ยนรหัสผ่าน
เมื่อผู้ใช้เลือกที่จะเปลี่ยนหรือลบรหัสผ่านในการตั้งค่า UI จะส่งคำสั่ง cryptfs changepw
ไปยัง vold
และ vold
จะเข้ารหัสดิสก์มาสเตอร์คีย์อีกครั้งด้วยรหัสผ่านใหม่
คุณสมบัติการเข้ารหัส
vold
และ init
สื่อสารกันโดยการตั้งค่าคุณสมบัติ นี่คือรายการของคุณสมบัติที่มีสำหรับการเข้ารหัส
คุณสมบัติของโวล
คุณสมบัติ | คำอธิบาย |
---|---|
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 |
คุณสมบัติเริ่มต้น
คุณสมบัติ | คำอธิบาย |
---|---|
ro.crypto.fs_crypto_blkdev | ตั้งค่าโดยคำสั่ง vold checkpw เพื่อใช้ในภายหลังโดยคำสั่ง vold restart |
ro.crypto.state unencrypted | ตั้งค่าโดย init เพื่อบอกว่าระบบนี้กำลังทำงานโดยไม่ได้เข้ารหัส /data ro.crypto.state encrypted ตั้งค่าโดย init เพื่อบอกว่าระบบนี้ทำงานด้วยการเข้ารหัส /data |
| คุณสมบัติทั้งห้านี้ถูกกำหนดโดย init เมื่อพยายามเมานต์ /data ด้วยพารามิเตอร์ที่ส่งผ่านจาก init.rc vold ใช้สิ่งเหล่านี้เพื่อตั้งค่าการแมป crypto |
ro.crypto.tmpfs_options | ตั้งค่าโดย init.rc พร้อมตัวเลือก init ควรใช้เมื่อติดตั้งระบบไฟล์ tmpfs /data |
เริ่มต้นการดำเนินการ
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,
การเข้ารหัสทั้งดิสก์คือกระบวนการเข้ารหัสข้อมูลผู้ใช้ทั้งหมดบนอุปกรณ์ Android โดยใช้คีย์เข้ารหัส เมื่อเข้ารหัสอุปกรณ์แล้ว ข้อมูลทั้งหมดที่สร้างโดยผู้ใช้จะถูกเข้ารหัสโดยอัตโนมัติก่อนที่จะส่งไปยังดิสก์ และการอ่านข้อมูลทั้งหมดจะถอดรหัสข้อมูลโดยอัตโนมัติก่อนที่จะส่งคืนไปยังกระบวนการเรียก
การเข้ารหัสทั้งดิสก์ถูกนำมาใช้กับ Android ในเวอร์ชัน 4.4 แต่ Android 5.0 ได้แนะนำคุณลักษณะใหม่เหล่านี้:
- สร้างการเข้ารหัสที่รวดเร็ว ซึ่งจะเข้ารหัสเฉพาะบล็อกที่ใช้แล้วบนพาร์ติชันข้อมูลเพื่อหลีกเลี่ยงการบูตครั้งแรกที่ใช้เวลานาน ขณะนี้ระบบไฟล์ ext4 และ f2fs เท่านั้นที่รองรับการเข้ารหัสที่รวดเร็ว
- เพิ่ม ธง
forceencrypt
fstab เพื่อเข้ารหัสในการบูตครั้งแรก - เพิ่มการรองรับรูปแบบและการเข้ารหัสโดยไม่ต้องใช้รหัสผ่าน
- เพิ่มที่เก็บข้อมูลคีย์เข้ารหัสที่สนับสนุนฮาร์ดแวร์โดยใช้ความสามารถในการลงนามของ Trusted Execution Environment (TEE) (เช่นใน TrustZone) โปรดดูรายละเอียดเพิ่มเติมใน การจัดเก็บคีย์ที่เข้ารหัส
ข้อควรระวัง: อุปกรณ์ที่อัปเกรดเป็น Android 5.0 แล้วเข้ารหัสแล้วอาจกลับสู่สถานะที่ไม่ได้เข้ารหัสโดยการรีเซ็ตข้อมูลเป็นค่าเริ่มต้น อุปกรณ์ Android 5.0 ใหม่ที่เข้ารหัสเมื่อบู๊ตครั้งแรกจะไม่สามารถกลับสู่สถานะที่ไม่ได้เข้ารหัสได้
วิธีการทำงานของการเข้ารหัสทั้งดิสก์ของ Android
การเข้ารหัสทั้งดิสก์ของ Android ใช้ dm-crypt
ซึ่งเป็นคุณลักษณะเคอร์เนลที่ทำงานที่ชั้นอุปกรณ์บล็อก ด้วยเหตุนี้ การเข้ารหัสจึงทำงานร่วมกับ Embedded MultiMediaCard ( eMMC) และอุปกรณ์แฟลชที่คล้ายกันซึ่งนำเสนอตัวเองในเคอร์เนลเป็นอุปกรณ์บล็อก ไม่สามารถเข้ารหัสด้วย YAFFS ซึ่งพูดโดยตรงกับชิปแฟลช NAND ดิบ
อัลกอริธึมการเข้ารหัสคือ 128 Advanced Encryption Standard (AES) พร้อมด้วย cipher-block chaining (CBC) และ ESSIV:SHA256 มาสเตอร์คีย์ถูกเข้ารหัสด้วย AES 128 บิตผ่านการเรียกไปยังไลบรารี OpenSSL คุณต้องใช้ 128 บิตขึ้นไปสำหรับคีย์ (โดยที่ 256 เป็นทางเลือก)
หมายเหตุ: OEM สามารถใช้ 128 บิตหรือสูงกว่าเพื่อเข้ารหัสมาสเตอร์คีย์ได้
ในการเปิดตัว Android 5.0 มีสถานะการเข้ารหัสสี่ประเภท:
- ค่าเริ่มต้น
- เข็มหมุด
- รหัสผ่าน
- ลวดลาย
เมื่อบู๊ตครั้งแรก อุปกรณ์จะสร้างมาสเตอร์คีย์ 128 บิตแบบสุ่ม จากนั้นแฮชด้วยรหัสผ่านเริ่มต้นและเกลือที่เก็บไว้ รหัสผ่านเริ่มต้นคือ: "default_password" อย่างไรก็ตาม แฮชผลลัพธ์ยังถูกเซ็นผ่าน TEE (เช่น TrustZone) ซึ่งใช้แฮชของลายเซ็นเพื่อเข้ารหัสคีย์หลัก
คุณสามารถค้นหารหัสผ่านเริ่มต้นที่กำหนดไว้ในไฟล์ cryptfs.cpp ของ Android Open Source Project
เมื่อผู้ใช้ตั้งค่า PIN/รหัสผ่าน หรือรหัสผ่านบนอุปกรณ์ เฉพาะคีย์ 128 บิตเท่านั้นที่จะถูกเข้ารหัสและจัดเก็บใหม่ (เช่น การเปลี่ยนแปลง PIN/รหัสผ่าน/รูปแบบของผู้ใช้จะไม่ทำให้เกิดการเข้ารหัสซ้ำของข้อมูลผู้ใช้) โปรดทราบว่า อุปกรณ์ที่มีการจัดการ อาจอยู่ภายใต้ข้อจำกัดของ PIN รูปแบบ หรือรหัสผ่าน
การเข้ารหัสถูกจัดการโดย init
และ vold
init
เรียก vold
และ vold ตั้งค่าคุณสมบัติเพื่อทริกเกอร์เหตุการณ์ใน init ส่วนอื่นๆ ของระบบยังดูที่คุณสมบัติเพื่อดำเนินการต่างๆ เช่น สถานะรายงาน ขอรหัสผ่าน หรือแจ้งให้รีเซ็ตเป็นค่าเริ่มต้นจากโรงงานในกรณีที่เกิดข้อผิดพลาดร้ายแรง ในการเรียกใช้คุณสมบัติการเข้ารหัสใน vold
ระบบจะใช้เครื่องมือบรรทัดคำสั่ง vdc
คำสั่ง cryptfs
: checkpw
, restart
, enablecrypto
, changepw
, cryptocomplete
, verifypw
, setfield
, getfield
, mountdefaultencrypted
, getpwtype
, getpw
และ clearpw
ในการเข้ารหัส ถอดรหัส หรือล้าง /data
data จะต้องไม่เมาต์ /data
อย่างไรก็ตาม เพื่อแสดงส่วนต่อประสานผู้ใช้ (UI) กรอบงานต้องเริ่มทำงานและกรอบงานต้องการ /data
เพื่อเรียกใช้ เพื่อแก้ไขปริศนานี้ ระบบไฟล์ชั่วคราวจะถูกติดตั้งบน /data
ซึ่งช่วยให้ Android สามารถขอรหัสผ่าน แสดงความคืบหน้า หรือแนะนำการล้างข้อมูลได้ตามต้องการ มีข้อจำกัดว่าในการเปลี่ยนจากระบบไฟล์ชั่วคราวเป็นระบบไฟล์ /data
จริง ระบบต้องหยุดทุกกระบวนการที่มีไฟล์เปิดอยู่บนระบบไฟล์ชั่วคราว และรีสตาร์ทกระบวนการเหล่านั้นบนระบบไฟล์ /data
จริง ในการทำเช่นนี้ บริการทั้งหมดต้องอยู่ในกลุ่มใดกลุ่มหนึ่งจากสามกลุ่ม: core
, main
และ late_start
-
core
: อย่าปิดเครื่องหลังจากเริ่มต้น -
main
: ปิดเครื่องแล้วรีสตาร์ทหลังจากป้อนรหัสผ่านของดิสก์ -
late_start
: ไม่เริ่มจนกว่า/data
จะถูกถอดรหัสและติดตั้ง
หากต้องการทริกเกอร์การกระทำเหล่านี้ คุณสมบัติ vold.decrypt
จะถูกตั้งค่าเป็น สตริงต่างๆ หากต้องการหยุดและเริ่มบริการใหม่ คำสั่ง init
คือ:
-
class_reset
: หยุดบริการ แต่อนุญาตให้รีสตาร์ทด้วย class_start -
class_start
: เริ่มบริการใหม่ -
class_stop
: หยุดบริการและเพิ่มแฟล็กSVC_DISABLED
บริการที่หยุดทำงานไม่ตอบสนองต่อclass_start
กระแส
มีสี่โฟลว์สำหรับอุปกรณ์ที่เข้ารหัส อุปกรณ์ได้รับการเข้ารหัสเพียงครั้งเดียวจากนั้นทำตามขั้นตอนการบูตตามปกติ
- เข้ารหัสอุปกรณ์ที่ไม่ได้เข้ารหัสก่อนหน้านี้:
- เข้ารหัสอุปกรณ์ใหม่ด้วย
forceencrypt
: การเข้ารหัสบังคับเมื่อบู๊ตครั้งแรก (เริ่มต้นใน Android L) - เข้ารหัสอุปกรณ์ที่มีอยู่: การเข้ารหัสที่เริ่มต้นโดยผู้ใช้ (Android K และรุ่นก่อนหน้า)
- เข้ารหัสอุปกรณ์ใหม่ด้วย
- บูตอุปกรณ์ที่เข้ารหัส:
- การเริ่มอุปกรณ์ที่เข้ารหัสโดยไม่มีรหัสผ่าน: การบูตอุปกรณ์ที่เข้ารหัสซึ่งไม่ได้ตั้งรหัสผ่าน (เกี่ยวข้องกับอุปกรณ์ที่ใช้ Android 5.0 และใหม่กว่า)
- การเริ่มอุปกรณ์ที่เข้ารหัสด้วยรหัสผ่าน: การบูตอุปกรณ์ที่เข้ารหัสซึ่งมีรหัสผ่านที่ตั้งไว้
นอกจากโฟลว์เหล่านี้แล้ว อุปกรณ์ยังสามารถเข้ารหัสล้มเหลวได้ /data
แต่ละโฟลว์มีคำอธิบายโดยละเอียดด้านล่าง
เข้ารหัสอุปกรณ์ใหม่ด้วยการบังคับเข้ารหัส
นี่เป็นการบู๊ตครั้งแรกตามปกติสำหรับอุปกรณ์ Android 5.0
- ตรวจหาระบบไฟล์ที่ไม่ได้เข้ารหัสด้วยการตั้งค่าสถานะ
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
- เมานต์
/data
จากนั้น
init
จะเมานต์/data
บน tmpfs RAMDisk โดยใช้พารามิเตอร์ที่รับมาจากro.crypto.tmpfs_options
ซึ่งตั้งค่าไว้ในinit.rc
- เริ่มกรอบ
vold
ตั้งค่าvold.decrypt
เป็นtrigger_restart_framework
ซึ่งจะดำเนินต่อตามกระบวนการบูตตามปกติ
เข้ารหัสอุปกรณ์ที่มีอยู่
นี่คือสิ่งที่เกิดขึ้นเมื่อคุณเข้ารหัส Android K หรืออุปกรณ์รุ่นก่อนหน้าที่ไม่ได้เข้ารหัสซึ่งถูกย้ายไปยัง L
กระบวนการนี้เริ่มต้นโดยผู้ใช้และเรียกว่า "inplace encryption" ในรหัส เมื่อผู้ใช้เลือกที่จะเข้ารหัสอุปกรณ์ UI จะตรวจสอบให้แน่ใจว่าแบตเตอรี่ชาร์จเต็มแล้วและเสียบอะแดปเตอร์ AC เพื่อให้มีพลังงานเพียงพอที่จะเสร็จสิ้นกระบวนการเข้ารหัส
คำเตือน: หากอุปกรณ์ไฟฟ้าหมดและปิดก่อนที่จะเข้ารหัสเสร็จ ข้อมูลไฟล์จะอยู่ในสถานะเข้ารหัสบางส่วน ต้องรีเซ็ตอุปกรณ์เป็นค่าเริ่มต้นและข้อมูลทั้งหมดจะสูญหาย
ในการเปิดใช้งานการเข้ารหัสแบบแทนที่ vold
จะเริ่มวนรอบเพื่ออ่านแต่ละส่วนของอุปกรณ์บล็อกจริง จากนั้นจึงเขียนไปยังอุปกรณ์บล็อกการเข้ารหัสลับ vold
ตรวจสอบเพื่อดูว่ามีการใช้เซกเตอร์หรือไม่ก่อนที่จะอ่านและเขียน ซึ่งทำให้การเข้ารหัสเร็วขึ้นมากบนอุปกรณ์ใหม่ที่มีข้อมูลเพียงเล็กน้อยหรือไม่มีเลย
สถานะของอุปกรณ์ : ตั้งค่า ro.crypto.state = "unencrypted"
และเรียกใช้ทริกเกอร์ init
on nonencrypted
เพื่อดำเนินการบูทต่อไป
- ตรวจสอบรหัสผ่าน
UI เรียก
vold
ด้วยคำสั่งcryptfs enablecrypto inplace
โดยที่passwd
เป็นรหัสผ่านล็อคหน้าจอของผู้ใช้ - ถอดกรอบ
vold
ตรวจสอบข้อผิดพลาด ส่งกลับ -1 หากไม่สามารถเข้ารหัส และพิมพ์เหตุผลในบันทึก หากสามารถเข้ารหัสได้ จะตั้งค่าคุณสมบัติvold.decrypt
เป็นtrigger_shutdown_framework
สิ่งนี้ทำให้init.rc
หยุดบริการในคลาสlate_start
และmain
- สร้างส่วนท้ายของการเข้ารหัสลับ
- สร้างไฟล์เบรดครัมบ์
- รีบูต
- ตรวจหาไฟล์เบรดครัมบ์
- เริ่มการเข้ารหัส
/data
จากนั้น
vold
จะตั้งค่าการแมป crypto ซึ่งสร้างอุปกรณ์บล็อก crypto เสมือนที่แมปบนอุปกรณ์บล็อกจริง แต่เข้ารหัสแต่ละเซกเตอร์ตามที่เขียน และถอดรหัสแต่ละเซกเตอร์เมื่ออ่าน จากนั้น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 ของแถบความคืบหน้า ซึ่งจะสอบถามคุณสมบัตินั้นทุก ๆ ห้าวินาทีและอัปเดตแถบความคืบหน้า ลูปการเข้ารหัสจะอัปเดตvold.encrypt_progress
ทุกครั้งที่เข้ารหัสพาร์ติชันอีกเปอร์เซ็นต์ - เมื่อ
/data
ถูกเข้ารหัส ให้อัปเดตส่วนท้ายของ cryptoเมื่อเข้ารหัส
/data
สำเร็จvold
จะล้างแฟล็กENCRYPTION_IN_PROGRESS
ในข้อมูลเมตาเมื่อปลดล็อคอุปกรณ์สำเร็จ รหัสผ่านจะถูกใช้เพื่อเข้ารหัสมาสเตอร์คีย์และส่วนท้ายของการเข้ารหัสลับจะได้รับการอัปเดต
หากการรีบูตล้มเหลวด้วยเหตุผลบางประการ
vold
จะตั้งค่าคุณสมบัติvold.encrypt_progress
เป็นerror_reboot_failed
และ UI ควรแสดงข้อความที่ขอให้ผู้ใช้กดปุ่มเพื่อรีบูต สิ่งนี้ไม่คาดว่าจะเกิดขึ้น
การเริ่มต้นอุปกรณ์ที่เข้ารหัสด้วยการเข้ารหัสเริ่มต้น
นี่คือสิ่งที่เกิดขึ้นเมื่อคุณบู๊ตอุปกรณ์ที่เข้ารหัสโดยไม่มีรหัสผ่าน เนื่องจากอุปกรณ์ Android 5.0 ได้รับการเข้ารหัสเมื่อบู๊ตครั้งแรก จึงไม่ควรตั้งรหัสผ่าน ดังนั้นจึงเป็นสถานะ การเข้ารหัสเริ่มต้น
- ตรวจหาการเข้ารหัส
/data
โดยไม่มีรหัสผ่านตรวจหาว่าอุปกรณ์ Android ได้รับการเข้ารหัสเนื่องจาก
/data
ไม่สามารถเมานต์ได้ และมีการตั้งค่าแฟล็กencryptable
หรือforceencrypt
อย่างใดอย่างหนึ่งvold
ตั้งค่าvold.decrypt
เป็นtrigger_default_encryption
ซึ่งเริ่มบริการdefaultcrypto
trigger_default_encryption
ตรวจสอบประเภทการเข้ารหัสเพื่อดูว่า/data
ถูกเข้ารหัสด้วยหรือไม่มีรหัสผ่าน - ถอดรหัส/ข้อมูล
สร้างอุปกรณ์
dm-crypt
เหนืออุปกรณ์บล็อกเพื่อให้อุปกรณ์พร้อมใช้งาน - เมานต์ / ข้อมูล
จากนั้น
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
และระบบพร้อมใช้งานแล้ว
Starting an encrypted device without default encryption
This is what happens when you boot up an encrypted device that has a set password. The device's password can be a pin, pattern, or password.
- Detect encrypted device with a password
Detect that the Android device is encrypted because the flag
ro.crypto.state = "encrypted"
vold
setsvold.decrypt
totrigger_restart_min_framework
because/data
is encrypted with a password. - Mount tmpfs
init
sets five properties to save the initial mount options given for/data
with parameters passed frominit.rc
.vold
uses these properties to set up the crypto mapping:-
ro.crypto.fs_type
-
ro.crypto.fs_real_blkdev
-
ro.crypto.fs_mnt_point
-
ro.crypto.fs_options
-
ro.crypto.fs_flags
(ASCII 8-digit hex number preceded by 0x)
-
- Start framework to prompt for password
The framework starts up and sees that
vold.decrypt
is set totrigger_restart_min_framework
. This tells the framework that it is booting on a tmpfs/data
disk and it needs to get the user password.First, however, it needs to make sure that the disk was properly encrypted. It sends the command
cryptfs cryptocomplete
tovold
.vold
returns 0 if encryption was completed successfully, -1 on internal error, or -2 if encryption was not completed successfully.vold
determines this by looking in the crypto metadata for theCRYPTO_ENCRYPTION_IN_PROGRESS
flag. If it's set, the encryption process was interrupted, and there is no usable data on the device. Ifvold
returns an error, the UI should display a message to the user to reboot and factory reset the device, and give the user a button to press to do so. - Decrypt data with password
Once
cryptfs cryptocomplete
is successful, the framework displays a UI asking for the disk password. The UI checks the password by sending the commandcryptfs checkpw
tovold
. If the password is correct (which is determined by successfully mounting the decrypted/data
at a temporary location, then unmounting it),vold
saves the name of the decrypted block device in the propertyro.crypto.fs_crypto_blkdev
and returns status 0 to the UI. If the password is incorrect, it returns -1 to the UI. - Stop framework
The UI puts up a crypto boot graphic and then calls
vold
with the commandcryptfs restart
.vold
sets the propertyvold.decrypt
totrigger_reset_main
, which causesinit.rc
to doclass_reset main
. This stops all services in the main class, which allows the tmpfs/data
to be unmounted. - Mount
/data
vold
then mounts the decrypted real/data
partition and prepares the new partition (which may never have been prepared if it was encrypted with the wipe option, which is not supported on first release). It sets the propertyvold.post_fs_data_done
to 0 and then setsvold.decrypt
totrigger_post_fs_data
. This causesinit.rc
to run itspost-fs-data
commands. They will create any necessary directories or links and then setvold.post_fs_data_done
to 1. Oncevold
sees the 1 in that property, it sets the propertyvold.decrypt
totrigger_restart_framework
. This causesinit.rc
to start services in classmain
again and also start services in classlate_start
for the first time since boot. - Start full framework
Now the framework boots all its services using the decrypted
/data
filesystem, and the system is ready for use.
Failure
A device that fails to decrypt might be awry for a few reasons. The device starts with the normal series of steps to boot:
- Detect encrypted device with a password
- Mount tmpfs
- Start framework to prompt for password
But after the framework opens, the device can encounter some errors:
- Password matches but cannot decrypt data
- User enters wrong password 30 times
If these errors are not resolved, prompt user to factory wipe :
If vold
detects an error during the encryption process, and if no data has been destroyed yet and the framework is up, vold
sets the property vold.encrypt_progress
to error_not_encrypted
. The UI prompts the user to reboot and alerts them the encryption process never started. If the error occurs after the framework has been torn down, but before the progress bar UI is up, vold
will reboot the system. If the reboot fails, it sets vold.encrypt_progress
to error_shutting_down
and returns -1; but there will not be anything to catch the error. This is not expected to happen.
If vold
detects an error during the encryption process, it sets vold.encrypt_progress
to error_partially_encrypted
and returns -1. The UI should then display a message saying the encryption failed and provide a button for the user to factory reset the device.
Storing the encrypted key
The encrypted key is stored in the crypto metadata. Hardware backing is implemented by using Trusted Execution Environment's (TEE) signing capability. Previously, we encrypted the master key with a key generated by applying scrypt to the user's password and the stored salt. In order to make the key resilient against off-box attacks, we extend this algorithm by signing the resultant key with a stored TEE key. The resultant signature is then turned into an appropriate length key by one more application of scrypt. This key is then used to encrypt and decrypt the master key. To store this key:
- Generate random 16-byte disk encryption key (DEK) and 16-byte salt.
- Apply scrypt to the user password and the salt to produce 32-byte intermediate key 1 (IK1).
- Pad IK1 with zero bytes to the size of the hardware-bound private key (HBK). Specifically, we pad as: 00 || IK1 || 00..00; one zero byte, 32 IK1 bytes, 223 zero bytes.
- Sign padded IK1 with HBK to produce 256-byte IK2.
- Apply scrypt to IK2 and salt (same salt as step 2) to produce 32-byte IK3.
- Use the first 16 bytes of IK3 as KEK and the last 16 bytes as IV.
- Encrypt DEK with AES_CBC, with key KEK, and initialization vector IV.
Changing the password
When a user elects to change or remove their password in settings, the UI sends the command cryptfs changepw
to vold
, and vold
re-encrypts the disk master key with the new password.
Encryption properties
vold
and init
communicate with each other by setting properties. Here is a list of available properties for encryption.
Vold properties
Property | คำอธิบาย |
---|---|
vold.decrypt trigger_encryption | Encrypt the drive with no password. |
vold.decrypt trigger_default_encryption | Check the drive to see if it is encrypted with no password. If it is, decrypt and mount it, else set vold.decrypt to trigger_restart_min_framework. |
vold.decrypt trigger_reset_main | Set by vold to shutdown the UI asking for the disk password. |
vold.decrypt trigger_post_fs_data | Set by vold to prep /data with necessary directories, et al. |
vold.decrypt trigger_restart_framework | Set by vold to start the real framework and all services. |
vold.decrypt trigger_shutdown_framework | Set by vold to shutdown the full framework to start encryption. |
vold.decrypt trigger_restart_min_framework | Set by vold to start the progress bar UI for encryption or prompt for password, depending on the value of ro.crypto.state . |
vold.encrypt_progress | When the framework starts up, if this property is set, enter the progress bar UI mode. |
vold.encrypt_progress 0 to 100 | The progress bar UI should display the percentage value set. |
vold.encrypt_progress error_partially_encrypted | The progress bar UI should display a message that the encryption failed, and give the user an option to factory reset the device. |
vold.encrypt_progress error_reboot_failed | The progress bar UI should display a message saying encryption completed, and give the user a button to reboot the device. This error is not expected to happen. |
vold.encrypt_progress error_not_encrypted | The progress bar UI should display a message saying an error occurred, no data was encrypted or lost, and give the user a button to reboot the system. |
vold.encrypt_progress error_shutting_down | The progress bar UI is not running, so it is unclear who will respond to this error. And it should never happen anyway. |
vold.post_fs_data_done 0 | Set by vold just before setting vold.decrypt to trigger_post_fs_data . |
vold.post_fs_data_done 1 | Set by init.rc or init.rc just after finishing the task post-fs-data . |
init properties
Property | คำอธิบาย |
---|---|
ro.crypto.fs_crypto_blkdev | Set by the vold command checkpw for later use by the vold command restart . |
ro.crypto.state unencrypted | Set by init to say this system is running with an unencrypted /data ro.crypto.state encrypted . Set by init to say this system is running with an encrypted /data . |
| These five properties are set by init when it tries to mount /data with parameters passed in from init.rc . vold uses these to setup the crypto mapping. |
ro.crypto.tmpfs_options | Set by init.rc with the options init should use when mounting the tmpfs /data filesystem. |
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