การเข้ารหัสทั้งดิสก์

การเข้ารหัสทั้งดิสก์เป็นกระบวนการเข้ารหัสข้อมูลผู้ใช้ทั้งหมดในอุปกรณ์ 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_start
  • class_start: รีสตาร์ทบริการ
  • class_stop: หยุดบริการและเพิ่ม Flag SVC_DISABLED บริการที่หยุดทำงานจะไม่ตอบสนองต่อ class_start

โฟลว์

อุปกรณ์ที่เข้ารหัสมีขั้นตอน 4 ขั้นตอน อุปกรณ์จะได้รับการเข้ารหัสเพียงครั้งเดียว จากนั้นระบบจะดำเนินการตามขั้นตอนการบูตตามปกติ

  • เข้ารหัสอุปกรณ์ที่ไม่ได้เข้ารหัสก่อนหน้านี้ โดยทำดังนี้
    • เข้ารหัสอุปกรณ์ใหม่ด้วย forceencrypt: การเข้ารหัสแบบบังคับ เมื่อบูตครั้งแรก (เริ่มตั้งแต่ Android L)
    • เข้ารหัสอุปกรณ์ที่มีอยู่: การเข้ารหัสที่ผู้ใช้เริ่ม (Android K และเก่ากว่า)
  • วิธีบูตอุปกรณ์ที่เข้ารหัส
    • การเริ่มอุปกรณ์ที่เข้ารหัสโดยไม่มีรหัสผ่าน: การบูตอุปกรณ์ที่เข้ารหัสซึ่งไม่มีการตั้งรหัสผ่าน (เกี่ยวข้องกับอุปกรณ์ที่ใช้ Android 5.0 ขึ้นไป)
    • การเริ่มอุปกรณ์ที่เข้ารหัสด้วยรหัสผ่าน: การบูตอุปกรณ์ที่เข้ารหัสซึ่งมีรหัสผ่านที่ตั้งไว้

นอกเหนือจากขั้นตอนเหล่านี้แล้ว อุปกรณ์อาจเข้ารหัส /data ไม่ได้ด้วย แต่ละขั้นตอนมีคำอธิบายโดยละเอียดด้านล่าง

เข้ารหัสอุปกรณ์เครื่องใหม่ด้วย forceencrypt

การบูตครั้งแรกนี้เป็นการเปิดเครื่องตามปกติของอุปกรณ์ Android 5.0

  1. ตรวจหาระบบไฟล์ที่ไม่ได้เข้ารหัสด้วย Flag forceencrypt

    /data ไม่ได้เข้ารหัส แต่จำเป็นต้องเข้ารหัสเนื่องจาก forceencrypt กำหนดไว้ ถอด /data

  2. เริ่มเข้ารหัส /data

    vold.decrypt = "trigger_encryption" ทริกเกอร์ init.rc ซึ่งทําให้ vold เข้ารหัส /data โดยไม่ใช้รหัสผ่าน (ไม่ได้ตั้งค่าไว้เนื่องจากควรเป็นอุปกรณ์ใหม่)

  3. ต่อเชื่อม tmpfs

    vold จะต่อเชื่อม tmpfs /data (โดยใช้ตัวเลือก tmpfs จาก ro.crypto.tmpfs_options) และตั้งค่าพร็อพเพอร์ตี้ vold.encrypt_progress เป็น 0 vold เตรียม tmpfs /data เพื่อบูตระบบที่เข้ารหัสและตั้งค่าพร็อพเพอร์ตี้ vold.decrypt เป็น trigger_restart_min_framework

  4. แสดงเฟรมเวิร์กเพื่อแสดงความคืบหน้า

    เนื่องจากอุปกรณ์แทบจะไม่มีข้อมูลที่จะเข้ารหัส แถบความคืบหน้าจึงจะไม่ปรากฏบ่อยนักเนื่องจากการเข้ารหัสเกิดขึ้นอย่างรวดเร็ว ดูรายละเอียดเพิ่มเติมเกี่ยวกับ UI ความคืบหน้าได้ที่หัวข้อเข้ารหัสอุปกรณ์ที่มีอยู่

  5. เมื่อ /data ได้รับการเข้ารหัส ให้นำเฟรมเวิร์กออก

    vold ตั้งค่า vold.decrypt เป็น trigger_default_encryption ซึ่งจะเริ่มต้นบริการ defaultcrypto (การดำเนินการนี้จะเริ่มต้นขั้นตอนด้านล่างสำหรับการต่อเชื่อมข้อมูลผู้ใช้ที่เข้ารหัสเริ่มต้น) trigger_default_encryption ตรวจสอบประเภทการเข้ารหัสเพื่อดูว่า /data ได้รับการเข้ารหัสโดยมีหรือไม่มีรหัสผ่าน เนื่องจากอุปกรณ์ Android 5.0 ได้รับการเข้ารหัสเมื่อบูตเครื่องครั้งแรก จึงไม่ควรมีการตั้งรหัสผ่าน เราจึงถอดรหัสและต่อเชื่อม /data

  6. Mount /data

    จากนั้น init จะต่อเชื่อม /data ใน RAMDisk ของ tmpfs โดยใช้พารามิเตอร์ที่รับจาก ro.crypto.tmpfs_options ซึ่งตั้งค่าไว้ใน init.rc

  7. Start Framework

    vold ตั้งค่า vold.decrypt เป็น trigger_restart_framework ซึ่งจะดําเนินการบูตตามปกติต่อ

เข้ารหัสอุปกรณ์ที่มีอยู่

การดำเนินการนี้จะมีผลเมื่อคุณเข้ารหัสอุปกรณ์ Android K หรือเก่ากว่าที่ไม่ได้เข้ารหัสซึ่งย้ายข้อมูลไปยัง L แล้ว

กระบวนการนี้เริ่มต้นโดยผู้ใช้และเรียกว่า "การเข้ารหัสในตำแหน่ง" ในโค้ด เมื่อผู้ใช้เลือกเข้ารหัสอุปกรณ์ UI จะตรวจสอบว่าแบตเตอรี่ชาร์จเต็มแล้วและเสียบอะแดปเตอร์ AC ไว้เพื่อให้มีพลังงานเพียงพอที่จะเข้ารหัสให้เสร็จสิ้น

คำเตือน: หากแบตเตอรี่ของอุปกรณ์หมดและปิดไปก่อนการเข้ารหัสเสร็จสิ้น ข้อมูลไฟล์จะยังคงอยู่ในสถานะที่เข้ารหัสบางส่วน อุปกรณ์ต้องรีเซ็ตเป็นค่าเริ่มต้นและข้อมูลทั้งหมดจะหายไป

หากต้องการเปิดใช้การเข้ารหัสในตำแหน่งเดิม vold จะเริ่มลูปเพื่ออ่านแต่ละภาคของอุปกรณ์บล็อกจริง แล้วเขียนลงในอุปกรณ์บล็อกการเข้ารหัส vold จะตรวจสอบว่าเซกเตอร์มีการใช้งานอยู่หรือไม่ก่อนที่จะอ่านและเขียน ซึ่งทำให้การเข้ารหัสเร็วขึ้นมากในอุปกรณ์ใหม่ที่มีข้อมูลน้อยหรือไม่มีข้อมูล

สถานะของอุปกรณ์: ตั้งค่า ro.crypto.state = "unencrypted" และเรียกใช้ทริกเกอร์ on nonencrypted init เพื่อบูตต่อ

  1. ตรวจสอบรหัสผ่าน

    UI จะเรียก vold ด้วยคําสั่ง cryptfs enablecrypto inplace โดยที่ passwd คือรหัสผ่านหน้าจอล็อกของผู้ใช้

  2. นําเฟรมเวิร์กออก

    vold จะตรวจสอบข้อผิดพลาด แสดงผล -1 หากเข้ารหัสไม่ได้ และพิมพ์เหตุผลในบันทึก หากเข้ารหัสได้ ระบบจะตั้งค่าพร็อพเพอร์ตี้ vold.decrypt เป็น trigger_shutdown_framework ซึ่งทำให้ init.rc หยุดให้บริการในคลาส late_start และ main

  3. สร้างส่วนท้ายเกี่ยวกับคริปโต
  4. สร้างไฟล์เบรดครัมบ์
  5. รีบูต
  6. ตรวจหาไฟล์เบรดครัมบ์
  7. เริ่มเข้ารหัส /data

    vold จะตั้งค่าการแมปการเข้ารหัส ซึ่งจะสร้างอุปกรณ์บล็อกการเข้ารหัสเสมือนจริงที่แมปกับอุปกรณ์บล็อกจริง แต่เข้ารหัสแต่ละภาคขณะเขียน และถอดรหัสแต่ละภาคขณะอ่าน vold จากนั้นจะสร้างและเขียนข้อมูลเมตาคริปโต

  8. ขณะเข้ารหัส ให้ต่อเชื่อม tmpfs

    vold จะต่อเชื่อม tmpfs /data (โดยใช้ตัวเลือก tmpfs จาก ro.crypto.tmpfs_options) และตั้งค่าพร็อพเพอร์ตี้ vold.encrypt_progress เป็น 0 vold เตรียม tmpfs /data สําหรับการบูตระบบที่เข้ารหัสและตั้งค่าพร็อพเพอร์ตี้ vold.decrypt เป็น trigger_restart_min_framework

  9. แสดงเฟรมเวิร์กเพื่อแสดงความคืบหน้า

    trigger_restart_min_framework ทําให้ init.rc เริ่มบริการระดับ main เมื่อเฟรมเวิร์กเห็นว่ามีการตั้งค่า vold.encrypt_progress เป็น 0 ระบบจะแสดงแถบความคืบหน้า UI ซึ่งจะค้นหาพร็อพเพอร์ตี้นั้นทุกๆ 5 วินาทีและอัปเดตแถบความคืบหน้า ลูปการเข้ารหัสจะอัปเดต vold.encrypt_progress ทุกครั้งที่เข้ารหัสอีกเปอร์เซ็นต์หนึ่งของพาร์ติชัน

  10. เมื่อ /data ได้รับการเข้ารหัส ให้อัปเดตส่วนท้ายการเข้ารหัส

    เมื่อเข้ารหัส /data เรียบร้อยแล้ว vold จะล้าง Flag ENCRYPTION_IN_PROGRESS ในข้อมูลเมตา

    เมื่อปลดล็อกอุปกรณ์สำเร็จแล้ว ระบบจะใช้รหัสผ่านเพื่อเข้ารหัสคีย์หลักและอัปเดตส่วนท้ายการเข้ารหัส

    หากการรีบูตไม่สำเร็จด้วยเหตุผลบางประการ vold จะตั้งค่าพร็อพเพอร์ตี้ vold.encrypt_progress เป็น error_reboot_failed และ UI ควรแสดงข้อความที่ขอให้ผู้ใช้กดปุ่มเพื่อรีบูต ซึ่งไม่ควรเกิดขึ้น

เริ่มอุปกรณ์ที่เข้ารหัสด้วยการเข้ารหัสเริ่มต้น

เหตุการณ์นี้จะเกิดขึ้นเมื่อคุณบูตอุปกรณ์ที่เข้ารหัสโดยไม่มีรหัสผ่าน เนื่องจากอุปกรณ์ Android 5.0 ได้รับการเข้ารหัสเมื่อบูตเครื่องครั้งแรก จึงไม่ควรมีการตั้งรหัสผ่าน และนี่คือสถานะการเข้ารหัสเริ่มต้น

  1. ตรวจหา /data ที่เข้ารหัสโดยไม่มีรหัสผ่าน

    ตรวจพบว่าอุปกรณ์ Android ได้รับการเข้ารหัสเนื่องจากไม่สามารถมา운ต์ /data และตั้งค่า Flag encryptable หรือ forceencrypt ไว้

    vold ตั้งค่า vold.decrypt เป็น trigger_default_encryption ซึ่งจะเริ่มต้นบริการ defaultcrypto trigger_default_encryption ตรวจสอบประเภทการเข้ารหัสเพื่อดูว่า /data ได้รับการเข้ารหัสด้วยหรือไม่มีรหัสผ่าน

  2. Decrypt /data

    สร้างอุปกรณ์ dm-crypt บนอุปกรณ์บล็อกเพื่อให้อุปกรณ์พร้อมใช้งาน

  3. ต่อเชื่อม /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 เป็นครั้งแรกนับตั้งแต่การบูต

  4. Start Framework

    ตอนนี้เฟรมเวิร์กจะบูตบริการทั้งหมดโดยใช้ /data ที่ถอดรหัสแล้ว และระบบก็พร้อมใช้งาน

เริ่มอุปกรณ์ที่เข้ารหัสโดยไม่มีการเข้ารหัสเริ่มต้น

สิ่งที่จะเกิดขึ้นเมื่อคุณบูตอุปกรณ์ที่เข้ารหัสซึ่งมีการตั้งรหัสผ่านไว้ รหัสผ่านของอุปกรณ์อาจเป็น PIN, รูปแบบ หรือรหัสผ่าน

  1. ตรวจหาอุปกรณ์ที่เข้ารหัสด้วยรหัสผ่าน

    ตรวจพบว่าอุปกรณ์ Android ได้รับการเข้ารหัสเนื่องจาก Flag ro.crypto.state = "encrypted"

    vold ตั้งค่า vold.decrypt เป็น trigger_restart_min_framework เนื่องจาก /data ได้รับการเข้ารหัสด้วยรหัสผ่าน

  2. ต่อเชื่อม tmpfs

    init ตั้งค่าพร็อพเพอร์ตี้ 5 รายการเพื่อบันทึกตัวเลือกการต่อเชื่อมเริ่มต้นให้กับ /data ด้วยพารามิเตอร์ที่ส่งมาจาก init.rc vold ใช้พร็อพเพอร์ตี้เหล่านี้เพื่อตั้งค่าการแมปคริปโต

    1. ro.crypto.fs_type
    2. ro.crypto.fs_real_blkdev
    3. ro.crypto.fs_mnt_point
    4. ro.crypto.fs_options
    5. ro.crypto.fs_flags (ตัวเลขฐาน 16 8 หลักของ ASCII ตามด้วย 0x)
  3. เริ่มเฟรมเวิร์กเพื่อแจ้งให้ป้อนรหัสผ่าน

    เฟรมเวิร์กเริ่มต้นขึ้นและพบว่า vold.decrypt มีการตั้งค่าเป็น trigger_restart_min_framework ซึ่งจะบอกเฟรมเวิร์กว่ากำลังบูตในดิสก์ tmpfs /data และต้องขอรหัสผ่านของผู้ใช้

    แต่ก่อนอื่น จะต้องตรวจสอบว่าดิสก์ได้รับการเข้ารหัสอย่างถูกต้อง โดยจะส่งคําสั่ง cryptfs cryptocomplete ไปยัง vold vold จะแสดงผลเป็น 0 หากการเข้ารหัสเสร็จสมบูรณ์ -1 หากมีข้อผิดพลาดภายใน หรือ -2 หากการเข้ารหัสไม่เสร็จสมบูรณ์ vold จะระบุข้อมูลนี้โดยดูที่ธง CRYPTO_ENCRYPTION_IN_PROGRESS ในข้อมูลเมตาของคริปโต หากตั้งค่าไว้ แสดงว่ากระบวนการเข้ารหัสถูกขัดจังหวะและไม่มีข้อมูลที่ใช้งานได้ในอุปกรณ์ หาก vold แสดงข้อผิดพลาด UI ควรแสดงข้อความให้ผู้ใช้รีบูตและรีเซ็ตอุปกรณ์เป็นค่าเริ่มต้น รวมถึงแสดงปุ่มให้ผู้ใช้กดเพื่อดำเนินการดังกล่าว

  4. ถอดรหัสข้อมูลด้วยรหัสผ่าน

    เมื่อ cryptfs cryptocomplete ดำเนินการเสร็จสมบูรณ์แล้ว เฟรมเวิร์กจะแสดง UI ที่ขอรหัสผ่านของดิสก์ UI จะตรวจสอบรหัสผ่านโดยส่งคําสั่ง cryptfs checkpw ไปยัง vold หากรหัสผ่านถูกต้อง (ซึ่งพิจารณาจากการต่อเชื่อม/dataที่ถอดรหัสแล้วในตำแหน่งชั่วคราวและถอดออกเรียบร้อยแล้ว) vold จะบันทึกชื่ออุปกรณ์บล็อกที่ถอดรหัสแล้วในพร็อพเพอร์ตี้ ro.crypto.fs_crypto_blkdev และแสดงสถานะ 0 ไปยัง UI หากรหัสผ่านไม่ถูกต้อง ระบบจะแสดงผล -1 ใน UI

  5. เฟรมเวิร์กหยุด

    UI จะแสดงกราฟิกการบูตคริปโต จากนั้นเรียกใช้ vold ด้วยคำสั่ง cryptfs restart vold ตั้งค่าพร็อพเพอร์ตี้ vold.decrypt เป็น trigger_reset_main ซึ่งทําให้ init.rc ทํา class_reset main ซึ่งจะหยุดบริการทั้งหมดในคลาสหลัก ซึ่งจะช่วยให้ยกเลิกการต่อเชื่อม tmpfs /data ได้

  6. 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 เป็นครั้งแรกนับตั้งแต่การบูต

  7. เริ่มใช้งานเฟรมเวิร์กแบบสมบูรณ์

    ตอนนี้เฟรมเวิร์กจะบูตบริการทั้งหมดโดยใช้/data ระบบไฟล์ที่ถอดรหัสแล้ว และระบบก็พร้อมใช้งาน

ไม่สำเร็จ

อุปกรณ์ที่ถอดรหัสไม่สำเร็จอาจมีปัญหาอยู่ 2-3 อย่าง อุปกรณ์จะเริ่มต้นด้วยชุดขั้นตอนปกติในการบูต ดังนี้

  1. ตรวจหาอุปกรณ์ที่เข้ารหัสด้วยรหัสผ่าน
  2. ต่อเชื่อม tmpfs
  3. เริ่มเฟรมเวิร์กเพื่อแจ้งให้ป้อนรหัสผ่าน

แต่หลังจากเปิดเฟรมเวิร์กแล้ว อุปกรณ์อาจพบข้อผิดพลาดบางอย่าง ดังนี้

  • รหัสผ่านตรงกันแต่ถอดรหัสข้อมูลไม่ได้
  • ผู้ใช้ป้อนรหัสผ่านไม่ถูกต้อง 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 ครั้ง จากนั้นระบบจะใช้คีย์นี้เพื่อเข้ารหัสและถอดรหัสคีย์หลัก วิธีจัดเก็บคีย์นี้

  1. สร้างคีย์การเข้ารหัสดิสก์ (DEK) 16 ไบต์และเกลือ 16 ไบต์แบบสุ่ม
  2. ใช้ Scrypt กับรหัสผ่านของผู้ใช้และ Salt เพื่อสร้างคีย์กลาง 32 ไบต์ 1 (IK1)
  3. เพิ่มค่า 0 ไบต์ลงใน IK1 จนมีขนาดเท่ากับคีย์ส่วนตัวที่เชื่อมโยงกับฮาร์ดแวร์ (HBK) กล่าวโดยละเอียดคือ เราจะเพิ่มค่าดังนี้ 00 || IK1 || 00..00; ไบต์ 0 1 ไบต์, IK1 32 ไบต์, 223 ไบต์ 0
  4. ลงชื่อ IK1 ที่เพิ่มค่าไว้ด้วย HBK เพื่อสร้าง IK2 ขนาด 256 ไบต์
  5. ใช้ Scrypt กับ IK2 และ Salt (Salt เดียวกับขั้นตอนที่ 2) เพื่อสร้าง IK3 ขนาด 32 ไบต์
  6. ใช้ 16 ไบต์แรกของ IK3 เป็น KEK และ 16 ไบต์สุดท้ายเป็น IV
  7. เข้ารหัส 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 ที่เข้ารหัส

ro.crypto.fs_type
ro.crypto.fs_real_blkdev
ro.crypto.fs_mnt_point
ro.crypto.fs_options
ro.crypto.fs_flags

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