เช่นเดียวกับซอฟต์แวร์เข้ารหัสดิสก์และไฟล์ส่วนใหญ่ การเข้ารหัสที่เก็บข้อมูลของ Android นั้นขึ้นอยู่กับคีย์การเข้ารหัสดิบที่มีอยู่ในหน่วยความจำของระบบเพื่อให้สามารถทำการเข้ารหัสได้ แม้ว่าการเข้ารหัสจะดำเนินการโดยฮาร์ดแวร์เฉพาะมากกว่าโดยซอฟต์แวร์ แต่โดยทั่วไปซอฟต์แวร์ยังคงต้องจัดการคีย์การเข้ารหัสดิบ
ซึ่งตามธรรมเนียมปฏิบัตินี้ไม่ได้มองว่าเป็นปัญหาเนื่องจากคีย์จะไม่ปรากฏระหว่างการโจมตีแบบออฟไลน์ ซึ่งเป็นประเภทหลักของการโจมตีที่การเข้ารหัสที่จัดเก็บข้อมูลมีไว้เพื่อป้องกัน อย่างไรก็ตาม มีความปรารถนาที่จะเพิ่มการป้องกันการโจมตีประเภทอื่นๆ เช่น การโจมตีแบบ Cold Boot และการโจมตีออนไลน์ที่ผู้โจมตีอาจสามารถรั่วไหลหน่วยความจำของระบบได้โดยไม่กระทบต่ออุปกรณ์อย่างเต็มที่
เพื่อแก้ปัญหานี้ Android 11 ได้แนะนำการสนับสนุนสำหรับ คีย์ที่หุ้มด้วย ฮาร์ดแวร์ ซึ่งมีการสนับสนุนฮาร์ดแวร์อยู่ คีย์ที่หุ้มด้วยฮาร์ดแวร์คือคีย์หน่วยเก็บข้อมูลที่รู้จักในรูปแบบดิบสำหรับฮาร์ดแวร์เฉพาะเท่านั้น ซอฟต์แวร์มองเห็นและทำงานกับคีย์เหล่านี้ในรูปแบบห่อหุ้ม (เข้ารหัส) เท่านั้น ฮาร์ดแวร์นี้ต้องสามารถสร้างและนำเข้าคีย์หน่วยเก็บข้อมูล การรวมคีย์หน่วยเก็บข้อมูลในรูปแบบชั่วคราวและระยะยาว สืบทอดคีย์ย่อย ตั้งโปรแกรมคีย์ย่อยหนึ่งคีย์ลงในเอ็นจินการเข้ารหัสแบบอินไลน์โดยตรง และส่งคืนคีย์ย่อยแยกต่างหากไปยังซอฟต์แวร์
หมายเหตุ : เอ็นจิ้นการ เข้ารหัสแบบอินไลน์ (หรือ ฮาร์ดแวร์เข้ารหัสแบบอินไลน์ ) หมายถึงฮาร์ดแวร์ที่เข้ารหัส/ถอดรหัสข้อมูลในขณะที่กำลังเดินทางไป/จากอุปกรณ์จัดเก็บข้อมูล โดยปกตินี่คือตัวควบคุมโฮสต์ UFS หรือ eMMC ที่ใช้ส่วนขยายการเข้ารหัสลับที่กำหนดโดยข้อกำหนด JEDEC ที่สอดคล้องกัน
ออกแบบ
ส่วนนี้นำเสนอการออกแบบของคุณลักษณะคีย์ที่หุ้มด้วยฮาร์ดแวร์ ซึ่งรวมถึงการสนับสนุนฮาร์ดแวร์ที่จำเป็นสำหรับคุณลักษณะนี้ การสนทนานี้เน้นที่ การเข้ารหัสตามไฟล์ (FBE) แต่โซลูชันนี้ใช้กับ การเข้ารหัสข้อมูลเมตา ด้วย
วิธีหนึ่งในการหลีกเลี่ยงการต้องใช้คีย์เข้ารหัสดิบในหน่วยความจำระบบคือเก็บไว้ในคีย์สล็อตของเอ็นจิ้นการเข้ารหัสแบบอินไลน์เท่านั้น อย่างไรก็ตาม วิธีการนี้ประสบปัญหาบางประการ:
- จำนวนคีย์การเข้ารหัสอาจเกินจำนวนคีย์สล็อต
- เครื่องมือเข้ารหัสลับแบบอินไลน์สามารถใช้เพื่อเข้ารหัส/ถอดรหัสบล็อคข้อมูลทั้งหมดบนดิสก์เท่านั้น อย่างไรก็ตาม ในกรณีของ FBE ซอฟต์แวร์ยังคงต้องสามารถทำงานเข้ารหัสอื่น ๆ ได้ เช่น การเข้ารหัสชื่อไฟล์และการรับตัวระบุคีย์ ซอฟต์แวร์ยังคงต้องเข้าถึงคีย์ FBE ดิบเพื่อทำงานอื่น
เพื่อหลีกเลี่ยงปัญหาเหล่านี้ คีย์หน่วยเก็บข้อมูลจะถูกสร้างขึ้นเป็น คีย์ที่หุ้มด้วยฮาร์ดแวร์ ซึ่งสามารถแกะและใช้งานได้โดยฮาร์ดแวร์เฉพาะเท่านั้น ซึ่งช่วยให้รองรับคีย์ได้ไม่จำกัดจำนวน นอกจากนี้ ลำดับชั้นของคีย์ถูกแก้ไขและย้ายบางส่วนไปยังฮาร์ดแวร์นี้ ซึ่งช่วยให้สามารถส่งคืนคีย์ย่อยไปยังซอฟต์แวร์สำหรับงานที่ไม่สามารถใช้เอ็นจินการเข้ารหัสแบบอินไลน์ได้
ลำดับชั้นที่สำคัญ
สามารถดึงคีย์จากคีย์อื่นๆ โดยใช้ KDF (ฟังก์ชันการได้มาของคีย์) เช่น HKDF ส่งผลให้มี ลำดับชั้นของคีย์
ไดอะแกรมต่อไปนี้แสดงลำดับชั้นของคีย์ทั่วไปสำหรับ FBE เมื่อ ไม่ได้ ใช้คีย์ที่หุ้มด้วยฮาร์ดแวร์:
คีย์คลาส FBE คือคีย์การเข้ารหัสแบบ Raw ที่ Android ส่งผ่านไปยังเคอร์เนล Linux เพื่อปลดล็อกชุดไดเรกทอรีที่เข้ารหัสโดยเฉพาะ เช่น ที่เก็บข้อมูลที่เข้ารหัสข้อมูลประจำตัวสำหรับผู้ใช้ Android โดยเฉพาะ (ในเคอร์เนล คีย์นี้เรียกว่า คีย์หลัก fscrypt ) จากคีย์นี้ เคอร์เนลได้รับคีย์ย่อยต่อไปนี้:
- ตัวระบุคีย์ ค่านี้ไม่ได้ใช้สำหรับการเข้ารหัส แต่เป็นค่าที่ใช้ในการระบุคีย์ที่มีการป้องกันไฟล์หรือไดเร็กทอรีเฉพาะ
- คีย์การเข้ารหัสเนื้อหาไฟล์
- คีย์การเข้ารหัสชื่อไฟล์
ในทางตรงกันข้าม ไดอะแกรมต่อไปนี้แสดงลำดับชั้นของคีย์สำหรับ FBE เมื่อใช้คีย์ที่หุ้มด้วยฮาร์ดแวร์:
เมื่อเทียบกับกรณีก่อนหน้านี้ มีการเพิ่มระดับเพิ่มเติมในลำดับชั้นของคีย์ และย้ายตำแหน่งคีย์การเข้ารหัสเนื้อหาไฟล์ โหนดรูทยังคงแสดงถึงคีย์ที่ Android ส่งผ่านไปยัง Linux เพื่อปลดล็อกชุดไดเรกทอรีที่เข้ารหัส อย่างไรก็ตาม ตอนนี้คีย์นั้นอยู่ในรูปแบบที่ปิดไว้ชั่วคราว และจะต้องส่งผ่านไปยังฮาร์ดแวร์เฉพาะก่อนจึงจะใช้งานได้ ฮาร์ดแวร์นี้ต้องใช้อินเทอร์เฟซสองอินเทอร์เฟซที่ใช้คีย์ที่ห่อหุ้มไว้ชั่วคราว:
- อินเทอร์เฟซเดียวในการรับ
inline_encryption_key
และตั้งโปรแกรมโดยตรงลงในคีย์ล็อตของเอ็นจิ้นการเข้ารหัสแบบอินไลน์ ซึ่งช่วยให้สามารถเข้ารหัส/ถอดรหัสเนื้อหาไฟล์ได้โดยไม่ต้องมีซอฟต์แวร์เข้าถึงคีย์ดิบ ในเคอร์เนลทั่วไปของ Android อินเทอร์เฟซนี้สอดคล้องกับการดำเนินการblk_ksm_ll_ops::keyslot_program
ซึ่งต้องใช้งานโดยไดรเวอร์การจัดเก็บข้อมูล - อินเทอร์เฟซเดียวในการรับและส่งคืน
sw_secret
("ความลับของซอฟต์แวร์" หรือเรียกอีกอย่างว่า "ความลับดิบ" ในบางสถานที่) ซึ่งเป็นคีย์ที่ Linux ใช้ในการรับคีย์ย่อยสำหรับทุกอย่างนอกเหนือจากการเข้ารหัสเนื้อหาไฟล์ ในเคอร์เนลทั่วไปของ Android อินเทอร์เฟซนี้สอดคล้องกับการดำเนินการblk_ksm_ll_ops::derive_raw_secret
ซึ่งต้องใช้งานโดยไดรเวอร์การจัดเก็บข้อมูล
ในการรับ inline_encryption_key
และ sw_secret
จากคีย์การจัดเก็บข้อมูลดิบ ฮาร์ดแวร์ต้องใช้ KDF ที่เข้ารหัสลับได้อย่างแข็งแกร่ง KDF นี้ต้องปฏิบัติตามแนวทางปฏิบัติที่ดีที่สุดของการเข้ารหัส จะต้องมีความแข็งแกร่งด้านความปลอดภัยอย่างน้อย 256 บิต นั่นคือเพียงพอสำหรับอัลกอริธึมที่ใช้ในภายหลัง นอกจากนี้ยังต้องใช้ป้ายกำกับ บริบท และ/หรือสตริงข้อมูลเฉพาะแอปพลิเคชันที่แตกต่างกันเมื่อได้รับคีย์ย่อยแต่ละประเภทเพื่อรับประกันว่าคีย์ย่อยที่เป็นผลลัพธ์จะถูกแยกออกด้วยการเข้ารหัส กล่าวคือ ความรู้ของคีย์ย่อยนั้นจะไม่เปิดเผยคีย์ย่อยอื่นๆ ไม่จำเป็นต้องขยายคีย์ เนื่องจากคีย์พื้นที่เก็บข้อมูลดิบเป็นคีย์แบบสุ่มที่เหมือนกันอยู่แล้ว
ในทางเทคนิค สามารถใช้ KDF ใดๆ ที่ตรงตามข้อกำหนดด้านความปลอดภัยได้ อย่างไรก็ตาม เพื่อวัตถุประสงค์ในการทดสอบ จำเป็นต้องนำ KDF เดิมไปใช้ใหม่ในโค้ดทดสอบ ปัจจุบัน KDF หนึ่งรายการได้รับการตรวจสอบและดำเนินการแล้ว สามารถพบได้ใน ซอร์สโค้ดสำหรับ vts_kernel_encryption_test
ขอแนะนำให้ฮาร์ดแวร์ใช้ KDF นี้ ซึ่งใช้ NIST SP 800-108 "KDF ในโหมดตัวนับ" โดยมี AES-256-CMAC เป็น PRF โปรดทราบว่าเพื่อให้เข้ากันได้ ทุกส่วนของอัลกอริทึมจะต้องเหมือนกัน รวมถึงตัวเลือกบริบทและป้ายกำกับของ KDF สำหรับแต่ละคีย์ย่อย
ห่อกุญแจ
เพื่อให้บรรลุเป้าหมายด้านความปลอดภัยของคีย์ที่หุ้มด้วยฮาร์ดแวร์ จึงมีการกำหนดการห่อคีย์สองประเภท:
- การ ตัดคำชั่วคราว : ฮาร์ดแวร์เข้ารหัสคีย์ดิบโดยใช้คีย์ซึ่งสร้างขึ้นแบบสุ่มทุกครั้งที่บู๊ตและจะไม่เปิดเผยภายนอกฮาร์ดแวร์โดยตรง
- การตัดคำระยะยาว : ฮาร์ดแวร์เข้ารหัสคีย์ดิบโดยใช้คีย์ถาวรที่ไม่ซ้ำกันซึ่งมีอยู่ในฮาร์ดแวร์ซึ่งไม่ได้เปิดเผยโดยตรงนอกฮาร์ดแวร์
คีย์ทั้งหมดที่ส่งผ่านไปยังเคอร์เนล Linux เพื่อปลดล็อกที่เก็บข้อมูลจะถูกห่อหุ้มไว้ชั่วคราว เพื่อให้แน่ใจว่าหากผู้โจมตีสามารถดึงคีย์ที่ใช้อยู่ออกจากหน่วยความจำระบบ คีย์นั้นจะใช้งานไม่ได้ไม่เพียงแต่ในอุปกรณ์เท่านั้น แต่ยังรวมถึงในอุปกรณ์ด้วยหลังจากรีบูต
ในเวลาเดียวกัน Android ยังคงต้องสามารถจัดเก็บคีย์เวอร์ชันที่เข้ารหัสไว้บนดิสก์เพื่อให้สามารถปลดล็อกได้ตั้งแต่แรก คีย์ดิบจะทำงานเพื่อจุดประสงค์นี้ อย่างไรก็ตาม ขอแนะนำไม่ให้มีคีย์ดิบอยู่ในหน่วยความจำระบบเลย เพื่อที่จะไม่สามารถแยกคีย์ดิบไปใช้นอกอุปกรณ์ได้ แม้ว่าจะแตกไฟล์ออกมาในขณะบู๊ตก็ตาม ด้วยเหตุนี้ จึงมีการกำหนดแนวคิดของการห่อระยะยาว
เพื่อรองรับการจัดการคีย์ที่รวมอยู่ในสองวิธีที่แตกต่างกัน ฮาร์ดแวร์ต้องใช้อินเทอร์เฟซต่อไปนี้:
- อินเทอร์เฟซสำหรับสร้างและนำเข้าคีย์หน่วยเก็บข้อมูล โดยส่งคืนในรูปแบบห่อหุ้มระยะยาว อินเทอร์เฟซเหล่านี้เข้าถึงได้ทางอ้อมผ่าน KeyMint และสอดคล้องกับแท็ก
TAG_STORAGE_KEY
KeyMint ความสามารถ "สร้าง" ถูกใช้โดยvold
เพื่อสร้างคีย์พื้นที่เก็บข้อมูลใหม่สำหรับ Android ในขณะที่ความสามารถ "นำเข้า" ถูกใช้โดยvts_kernel_encryption_test
เพื่อนำเข้าคีย์ทดสอบ - อินเทอร์เฟซสำหรับแปลงคีย์หน่วยเก็บข้อมูลที่ห่อหุ้มระยะยาวเป็นคีย์หน่วยเก็บข้อมูลที่ห่อหุ้มไว้ชั่วคราว ซึ่งสอดคล้องกับวิธี
convertStorageKeyToEphemeral
KeyMint วิธีนี้ใช้โดยทั้งvold
และvts_kernel_encryption_test
เพื่อปลดล็อกที่เก็บข้อมูล
อัลกอริทึมการตัดคีย์เป็นรายละเอียดการนำไปใช้ แต่ควรใช้ AEAD ที่รัดกุม เช่น AES-256-GCM พร้อม IV แบบสุ่ม
จำเป็นต้องเปลี่ยนซอฟต์แวร์
AOSP มีเฟรมเวิร์กพื้นฐานสำหรับรองรับคีย์ที่หุ้มด้วยฮาร์ดแวร์อยู่แล้ว ซึ่งรวมถึงการสนับสนุนในส่วนประกอบ userspace เช่น vold
เช่นเดียวกับการสนับสนุนเคอร์เนล Linux ใน blk-crypto , fscrypt และ dm-default-key
อย่างไรก็ตาม จำเป็นต้องมีการเปลี่ยนแปลงเฉพาะการนำไปใช้
การเปลี่ยนแปลงของ KeyMint
ต้องแก้ไขการใช้งาน KeyMint ของอุปกรณ์เพื่อรองรับ TAG_STORAGE_KEY
และใช้เมธอด convertStorageKeyToEphemeral
ใน Keymaster มีการใช้ exportKey
แทน convertStorageKeyToEphemeral
การเปลี่ยนแปลงเคอร์เนลลินุกซ์
ไดรเวอร์เคอร์เนล Linux สำหรับเอ็นจิ้นการเข้ารหัสแบบอินไลน์ของอุปกรณ์จะต้องถูกแก้ไขเพื่อตั้งค่า BLK_CRYPTO_FEATURE_WRAPPED_KEYS
ทำให้การทำงาน keyslot_program()
และ keyslot_evict()
รองรับการเขียนโปรแกรม/ขับไล่คีย์ที่หุ้มด้วยฮาร์ดแวร์ และใช้การดำเนินการ 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
สำหรับรายละเอียดเพิ่มเติม โปรดดู เอกสารการเข้ารหัสข้อมูลเมตา