การเข้ารหัสพื้นที่เก็บข้อมูลของ Android มักจะอาศัยคีย์การเข้ารหัสที่อยู่ในหน่วยความจำของระบบเหมือนกับซอฟต์แวร์เข้ารหัสไฟล์ส่วนใหญ่ เพื่อให้สามารถดำเนินการเข้ารหัสได้ แม้ว่าการเข้ารหัสจะดำเนินการโดยฮาร์ดแวร์เฉพาะแทนที่จะเป็นซอฟต์แวร์ แต่โดยทั่วไปซอฟต์แวร์ยังคงต้องจัดการคีย์การเข้ารหัสดิบ
โดยทั่วไปแล้ว ปัญหานี้ไม่ได้ถูกมองว่าเป็นปัญหา เนื่องจากคีย์จะไม่ปรากฏขึ้นในระหว่างการโจมตีแบบออฟไลน์ ซึ่งเป็นประเภทการโจมตีหลักที่การเข้ารหัสพื้นที่เก็บข้อมูลมีไว้เพื่อป้องกัน อย่างไรก็ตาม เราต้องการมอบการป้องกันที่เพิ่มขึ้นจากการโจมตีประเภทอื่นๆ เช่น การโจมตีแบบ Cold Boot และการโจมตีทางออนไลน์ที่ผู้โจมตีอาจสามารถรั่วไหลหน่วยความจำของระบบได้โดยไม่ต้องทำให้อุปกรณ์เสียหายอย่างสมบูรณ์
Android 11 จึงแก้ปัญหานี้ด้วยการรองรับคีย์ที่รวมไว้ในฮาร์ดแวร์เมื่ออุปกรณ์รองรับฮาร์ดแวร์ คีย์ที่รวมไว้ในฮาร์ดแวร์คือคีย์พื้นที่เก็บข้อมูลที่มีเฉพาะฮาร์ดแวร์เฉพาะเท่านั้นที่ทราบในรูปแบบไฟล์ดิบ ซอฟต์แวร์จะมองเห็นและทำงานกับคีย์เหล่านี้ในรูปแบบที่รวมไว้ (เข้ารหัส) เท่านั้น ฮาร์ดแวร์นี้ต้องสามารถสร้างและนําเข้าคีย์พื้นที่เก็บข้อมูล แพ็กเกจคีย์พื้นที่เก็บข้อมูลในรูปแบบชั่วคราวและระยะยาว ดึงข้อมูลคีย์ย่อย เขียนโปรแกรมคีย์ย่อย 1 คีย์ลงในเครื่องมือเข้ารหัสในบรรทัดโดยตรง และแสดงผลคีย์ย่อยแยกต่างหากไปยังซอฟต์แวร์
หมายเหตุ: เครื่องมือเข้ารหัสแบบอินไลน์ (หรือฮาร์ดแวร์การเข้ารหัสแบบอินไลน์) หมายถึงฮาร์ดแวร์ที่เข้ารหัส/ถอดรหัสข้อมูลขณะส่งไปยัง/จากอุปกรณ์เก็บข้อมูล โดยปกติแล้วจะเป็นตัวควบคุมโฮสต์ UFS หรือ eMMC ที่ใช้ส่วนขยายการเข้ารหัสที่ระบุไว้ในข้อกำหนด JEDEC ที่เกี่ยวข้อง
การออกแบบ
ส่วนนี้จะแสดงการออกแบบฟีเจอร์คีย์ที่รวมอยู่ในฮาร์ดแวร์ รวมถึงฮาร์ดแวร์ที่จำเป็นต้องใช้ การพูดคุยนี้มุ่งเน้นที่การเข้ารหัสตามไฟล์ (FBE) แต่โซลูชันนี้ก็ใช้กับการเข้ารหัสข้อมูลเมตาด้วยเช่นกัน
วิธีหนึ่งในการหลีกเลี่ยงการใช้คีย์การเข้ารหัสดิบในหน่วยความจำของระบบคือการเก็บคีย์ไว้ในช่องคีย์ของเครื่องมือเข้ารหัสแบบอินไลน์เท่านั้น อย่างไรก็ตาม วิธีการนี้อาจพบปัญหาบางอย่าง ดังนี้
- จำนวนคีย์การเข้ารหัสอาจมากกว่าจำนวนช่องเก็บคีย์
- โดยปกติแล้ว เครื่องมือเข้ารหัสแบบอินไลน์จะสูญเสียเนื้อหาของช่องคีย์หากรีเซ็ตตัวควบคุมพื้นที่เก็บข้อมูล (โดยปกติคือ UFS หรือ eMMC) รีเซ็ตตัวควบคุมพื้นที่เก็บข้อมูลเป็นขั้นตอนการกู้คืนข้อผิดพลาดมาตรฐานที่จะดำเนินการหากเกิดข้อผิดพลาดบางอย่างเกี่ยวกับพื้นที่เก็บข้อมูลขึ้น ซึ่งข้อผิดพลาดดังกล่าวอาจเกิดขึ้นได้ทุกเมื่อ ดังนั้น เมื่อใช้การเข้ารหัสในบรรทัด ระบบปฏิบัติการต้องพร้อมที่จะเขียนโปรแกรมช่องคีย์ใหม่เสมอโดยที่ผู้ใช้ไม่ต้องดำเนินการใดๆ
- เครื่องมือเข้ารหัสในบรรทัดใช้ได้เฉพาะกับการเข้ารหัส/ถอดรหัสบล็อกข้อมูลทั้งหมดในดิสก์ อย่างไรก็ตาม ในกรณีของ FBE ซอฟต์แวร์ยังคงต้องทํางานด้านการเข้ารหัสลับอื่นๆ ได้ เช่น การเข้ารหัสชื่อไฟล์และการสร้างตัวระบุคีย์ ซอฟต์แวร์จะยังคงต้องเข้าถึงคีย์ FBE ดิบเพื่อดำเนินการอื่นๆ นี้
เพื่อหลีกเลี่ยงปัญหาเหล่านี้ ระบบจะเปลี่ยนคีย์พื้นที่เก็บข้อมูลเป็นคีย์ที่รวมไว้ในฮาร์ดแวร์แทน ซึ่งจะถอดออกและใช้ได้โดยฮาร์ดแวร์เฉพาะเท่านั้น ซึ่งทำให้รองรับคีย์ได้ไม่จำกัดจำนวน นอกจากนี้ ระบบจะแก้ไขลําดับชั้นของคีย์และย้ายบางส่วนไปยังฮาร์ดแวร์นี้ ซึ่งจะช่วยให้ส่งคีย์ย่อยกลับไปที่ซอฟต์แวร์สําหรับงานที่ไม่สามารถใช้เครื่องมือเข้ารหัสแบบอินไลน์ได้
ลําดับชั้นของคีย์
คีย์จะมาจากคีย์อื่นๆ ได้โดยใช้ KDF (ฟังก์ชันการสร้างคีย์) เช่น HKDF ซึ่งจะทำให้เกิดลําดับชั้นคีย์
แผนภาพต่อไปนี้แสดงลําดับชั้นของคีย์ทั่วไปสําหรับ FBE เมื่อไม่ได้ใช้คีย์ที่รวมไว้ในฮาร์ดแวร์
คีย์คลาส FBE คือคีย์การเข้ารหัสดิบที่ Android ส่งผ่านไปยังเคอร์เนลของ Linux เพื่อปลดล็อกชุดไดเรกทอรีที่เข้ารหัสบางชุด เช่น พื้นที่เก็บข้อมูลที่เข้ารหัสข้อมูลเข้าสู่ระบบสำหรับผู้ใช้ Android บางราย (ในเคอร์เนล คีย์นี้เรียกว่าคีย์หลัก fscrypt) จากคีย์นี้ เคอร์เนลจะสร้างคีย์ย่อยต่อไปนี้
- ตัวระบุคีย์ ค่านี้ไม่ได้ใช้สำหรับการเข้ารหัส แต่เป็นค่าที่ใช้ระบุคีย์ที่ใช้ปกป้องไฟล์หรือไดเรกทอรีหนึ่งๆ
- คีย์การเข้ารหัสเนื้อหาไฟล์
- คีย์การเข้ารหัสชื่อไฟล์
ในทางตรงกันข้าม แผนภาพต่อไปนี้แสดงลำดับชั้นคีย์สำหรับ FBE เมื่อใช้คีย์ที่ห่อด้วยฮาร์ดแวร์
เมื่อเทียบกับกรณีก่อนหน้านี้ จะมีการเพิ่มลําดับชั้นอีกระดับลงในลําดับชั้นคีย์ และย้ายคีย์การเข้ารหัสเนื้อหาไฟล์ โหนดรูทยังคงแสดงคีย์ที่ Android ส่งไปยัง Linux เพื่อปลดล็อกชุดไดเรกทอรีที่เข้ารหัส แต่ตอนนี้คีย์ดังกล่าวอยู่ในรูปแบบที่รวมไว้ชั่วคราว และจะต้องส่งไปยังฮาร์ดแวร์เฉพาะจึงจะใช้ได้ ฮาร์ดแวร์นี้ต้องใช้อินเทอร์เฟซ 2 รายการที่ใช้คีย์ที่ห่อหุ้มชั่วคราว:
- อินเทอร์เฟซเดียวสำหรับดึงข้อมูล
inline_encryption_key
และตั้งโปรแกรมลงในช่องคีย์ของเครื่องมือเข้ารหัสแบบอินไลน์โดยตรง การดำเนินการนี้จะอนุญาตให้เข้ารหัส/ถอดรหัสเนื้อหาของไฟล์ได้โดยที่ซอฟต์แวร์ไม่มีสิทธิ์เข้าถึงคีย์ดิบ ในเคอร์เนลทั่วไปของ Android อินเทอร์เฟซนี้จะสอดคล้องกับการดำเนินการblk_crypto_ll_ops::keyslot_program
ซึ่งไดรเวอร์พื้นที่เก็บข้อมูลต้องติดตั้งใช้งาน - อินเทอร์เฟซ 1 รายการสำหรับดึงข้อมูลและแสดงผล
sw_secret
("ความลับของซอฟต์แวร์" หรือที่เรียกว่า "ความลับดิบ" ในบางที่) ซึ่งเป็นคีย์ที่ Linux ใช้ดึงข้อมูลคีย์ย่อยสำหรับทุกอย่างที่ไม่ใช่การเข้ารหัสเนื้อหาไฟล์ ในเคอร์เนลทั่วไปของ Android อินเทอร์เฟซนี้จะสอดคล้องกับการดำเนินการblk_crypto_ll_ops::derive_sw_secret
ซึ่งไดรเวอร์พื้นที่เก็บข้อมูลต้องติดตั้งใช้งาน
หากต้องการดึงข้อมูล inline_encryption_key
และ sw_secret
จากคีย์พื้นที่เก็บข้อมูลดิบ ฮาร์ดแวร์ต้องใช้ KDF ที่รัดกุมทางวิทยาการเข้ารหัส KDF นี้ต้องเป็นไปตามแนวทางปฏิบัติแนะนำด้านวิทยาการเข้ารหัส โดยต้องมีระดับความปลอดภัยอย่างน้อย 256 บิต ซึ่งเพียงพอสำหรับอัลกอริทึมที่จะใช้ในภายหลัง นอกจากนี้ยังต้องใช้ป้ายกำกับ บริบท และสตริงข้อมูลเฉพาะแอปที่แตกต่างกันเมื่อดึงข้อมูลคีย์ย่อยแต่ละประเภท เพื่อรับประกันว่าคีย์ย่อยที่ได้จะแยกออกมาแบบเข้ารหัส กล่าวคือความรู้เกี่ยวกับคีย์ใดคีย์หนึ่งจะไม่เปิดเผยอื่นใดเลย คุณไม่จำเป็นต้องเพิ่มความยาวคีย์ เนื่องจากคีย์พื้นที่เก็บข้อมูลดิบเป็นคีย์แบบสุ่มสม่ำเสมออยู่แล้ว
ในทางเทคนิคแล้ว คุณสามารถใช้ KDF ใดก็ได้ที่เป็นไปตามข้อกำหนดด้านความปลอดภัย
อย่างไรก็ตาม เพื่อการทดสอบ คุณจำเป็นต้องติดตั้งใช้งาน KDF เดียวกันอีกครั้งในโค้ดทดสอบ ปัจจุบัน KDF 1 รายการได้รับการตรวจสอบและนำไปใช้แล้ว จะอยู่ในซอร์สโค้ดสำหรับ vts_kernel_encryption_test
ขอแนะนำให้ฮาร์ดแวร์ใช้ KDF นี้ ซึ่งใช้ NIST SP 800-108 "KDF ในโหมดตัวนับ" ที่มี AES-256-CMAC เป็น PRF โปรดทราบว่าอัลกอริทึมทุกส่วนต้องเหมือนกัน รวมถึงการเลือกบริบท KDF และป้ายกำกับสำหรับคีย์ย่อยแต่ละรายการ จึงจะใช้งานร่วมกันได้
การห่อคีย์
เราได้กำหนดการรวมคีย์ไว้ 2 ประเภทเพื่อให้บรรลุเป้าหมายด้านความปลอดภัยของคีย์ที่ห่อด้วยฮาร์ดแวร์
- การรวมข้อมูลชั่วคราว: ฮาร์ดแวร์จะเข้ารหัสคีย์ดิบโดยใช้คีย์ที่สร้างขึ้นแบบสุ่มทุกครั้งที่บูตและไม่แสดงภายนอกฮาร์ดแวร์โดยตรง
- การรวมข้อมูลในระยะยาว: ฮาร์ดแวร์จะเข้ารหัสคีย์ดิบโดยใช้คีย์ถาวรที่ไม่ซ้ำกันซึ่งฝังอยู่ในฮาร์ดแวร์ ซึ่งไม่ได้เปิดเผยภายนอกฮาร์ดแวร์โดยตรง
คีย์ทั้งหมดที่ส่งไปยังเคอร์เนล Linux เพื่อปลดล็อกพื้นที่เก็บข้อมูลจะได้รับการรวมไว้ชั่วคราว วิธีนี้ช่วยให้มั่นใจว่าหากผู้โจมตีดึงคีย์ที่ใช้งานอยู่ออกจากหน่วยความจำของระบบได้ คีย์ดังกล่าวก็จะใช้ไม่ได้อีกนอกจากปิดอุปกรณ์ แต่ยังในอุปกรณ์หลังจากรีบูตด้วย
ในขณะเดียวกัน Android ยังต้องจัดเก็บคีย์เวอร์ชันที่เข้ารหัสไว้ในดิสก์เพื่อให้ปลดล็อกได้ตั้งแต่แรก ในกรณีนี้ คุณสามารถใช้คีย์ดิบได้ อย่างไรก็ตาม คุณไม่ควรเก็บคีย์ดิบไว้ในหน่วยความจำของระบบเลย เพื่อไม่ให้มีการนำคีย์ดิบไปใช้นอกอุปกรณ์ แม้ว่าจะดึงข้อมูลคีย์ดิบออกเมื่อทำการบูตก็ตาม ด้วยเหตุนี้ แนวคิดของการรวม ในระยะยาวจึงได้รับการกำหนดขึ้น
ฮาร์ดแวร์ต้องใช้อินเทอร์เฟซต่อไปนี้เพื่อรองรับการจัดการคีย์ที่รวมอยู่ใน 2 วิธีนี้
- อินเทอร์เฟซสำหรับสร้างและนำเข้าคีย์พื้นที่เก็บข้อมูล ซึ่งแสดงผลคีย์ในรูปแบบที่รวมไว้ระยะยาว อินเทอร์เฟซเหล่านี้เข้าถึงได้แบบอ้อมผ่าน KeyMint และสอดคล้องกับ
TAG_STORAGE_KEY
แท็ก KeyMintvold
จะใช้ความสามารถ "สร้าง" เพื่อสร้างคีย์พื้นที่เก็บข้อมูลใหม่สำหรับ Android ส่วนvts_kernel_encryption_test
จะใช้ความสามารถ "นําเข้า" เพื่อนําเข้าคีย์ทดสอบ - อินเทอร์เฟซสำหรับแปลงคีย์พื้นที่เก็บข้อมูลแบบรวมระยะยาวเป็นคีย์พื้นที่เก็บข้อมูลที่รวมอยู่ด้วยชั่วคราว ซึ่งสอดคล้องกับวิธี
convertStorageKeyToEphemeral
KeyMint ทั้งvold
และvts_kernel_encryption_test
ใช้วิธีการนี้เพื่อปลดล็อกพื้นที่เก็บข้อมูล
อัลกอริทึมการรวมคีย์เป็นรายละเอียดการใช้งาน แต่ควรใช้ AEAD ที่มีประสิทธิภาพสูง เช่น AES-256-GCM ที่มี IV แบบสุ่ม
ต้องมีการเปลี่ยนแปลงซอฟต์แวร์
AOSP มีเฟรมเวิร์กพื้นฐานที่รองรับคีย์ที่รวมไว้ในฮาร์ดแวร์อยู่แล้ว ซึ่งรวมถึงการรองรับคอมโพเนนต์พื้นที่ผู้ใช้ เช่น vold
และการสนับสนุนเคอร์เนลของ Linux ใน blk-crypto, fscrypt และ dm-default-key
แต่จำเป็นต้องมีการเปลี่ยนแปลงเฉพาะการติดตั้งใช้งานบางอย่าง
การเปลี่ยนแปลงของ KeyMint
การติดตั้งใช้งาน KeyMint ของอุปกรณ์ต้องได้รับการแก้ไขให้รองรับ TAG_STORAGE_KEY
และใช้วิธีการ convertStorageKeyToEphemeral
ใน Keymaster มีการใช้ exportKey
แทน convertStorageKeyToEphemeral
การเปลี่ยนแปลงเคอร์เนล Linux
ต้องแก้ไขไดรเวอร์เคอร์เนล Linux สำหรับเครื่องมือเข้ารหัสแบบอินไลน์ของอุปกรณ์เพื่อรองรับคีย์ที่รวมไว้ในฮาร์ดแวร์
สำหรับเคอร์เนล android14
ขึ้นไป ให้ตั้งค่า BLK_CRYPTO_KEY_TYPE_HW_WRAPPED
ใน blk_crypto_profile::key_types_supported
, สร้าง blk_crypto_ll_ops::keyslot_program
และ blk_crypto_ll_ops::keyslot_evict
รองรับการเขียนโปรแกรม/การลบคีย์ที่รวมไว้ในฮาร์ดแวร์ และติดตั้งใช้งาน blk_crypto_ll_ops::derive_sw_secret
สำหรับเคอร์เนล android12
และ android13
ให้ตั้งค่า BLK_CRYPTO_FEATURE_WRAPPED_KEYS
ใน blk_keyslot_manager::features
สร้าง blk_ksm_ll_ops::keyslot_program
และ blk_ksm_ll_ops::keyslot_evict
รองรับการเขียนโปรแกรม/การลบคีย์ที่รวมไว้ในฮาร์ดแวร์ และติดตั้งใช้งาน blk_ksm_ll_ops::derive_raw_secret
สําหรับเคอร์เนล android11
ให้ตั้งค่า BLK_CRYPTO_FEATURE_WRAPPED_KEYS
ใน keyslot_manager::features
สร้าง keyslot_mgmt_ll_ops::keyslot_program
และ keyslot_mgmt_ll_ops::keyslot_evict
รองรับการเขียนโปรแกรม/การลบคีย์ที่รวมไว้ในฮาร์ดแวร์ และติดตั้งใช้งาน keyslot_mgmt_ll_ops::derive_raw_secret
การทดสอบ
แม้ว่าการเข้ารหัสด้วยคีย์ที่ห่อด้วยฮาร์ดแวร์จะทดสอบได้ยากกว่าการเข้ารหัสด้วยคีย์มาตรฐาน แต่ก็ยังสามารถทดสอบได้โดยนำเข้าคีย์ทดสอบ และนำการสืบค้นคีย์ที่ฮาร์ดแวร์ทำมาใช้ใหม่ ซึ่งติดตั้งใช้งานใน vts_kernel_encryption_test
วิธีทำการทดสอบ
มีดังนี้
atest -v vts_kernel_encryption_test
อ่านบันทึกการทดสอบและยืนยันว่าไม่ได้ข้ามกรอบการทดสอบคีย์ที่ปกปิดด้วยฮาร์ดแวร์ (เช่น FBEPolicyTest.TestAesInlineCryptOptimizedHwWrappedKeyPolicy
และ DmDefaultKeyTest.TestHwWrappedKey
) เนื่องจากระบบตรวจไม่พบคีย์ที่ห่อด้วยฮาร์ดแวร์ เนื่องจากผลการทดสอบยังคง "ผ่าน" อยู่ในกรณีดังกล่าว
เปิดใช้คีย์
เมื่อการรองรับคีย์ที่รวมไว้ในฮาร์ดแวร์ของอุปกรณ์ทำงานได้อย่างถูกต้องแล้ว คุณสามารถทําการเปลี่ยนแปลงต่อไปนี้ในไฟล์ fstab
ของอุปกรณ์เพื่อให้ Android ใช้ไฟล์ดังกล่าวสําหรับ FBE และการเข้ารหัสข้อมูลเมตา
- FBE: เพิ่มแฟล็ก
wrappedkey_v0
ในพารามิเตอร์fileencryption
เช่น ใช้fileencryption=::inlinecrypt_optimized+wrappedkey_v0
ดูรายละเอียดเพิ่มเติมได้ในเอกสารประกอบ FBE - การเข้ารหัสข้อมูลเมตา: เพิ่มแฟล็ก
wrappedkey_v0
ในพารามิเตอร์metadata_encryption
เช่น ใช้metadata_encryption=:wrappedkey_v0
ดูรายละเอียดเพิ่มเติมได้ในเอกสารประกอบเกี่ยวกับการเข้ารหัสข้อมูลเมตา