กุญแจห่อฮาร์ดแวร์

การเข้ารหัสพื้นที่เก็บข้อมูลของ Android เดิมทีอาศัยคีย์การเข้ารหัสดิบที่อยู่ในหน่วยความจำของระบบเพื่อให้ทำการเข้ารหัสได้ เช่นเดียวกับซอฟต์แวร์การเข้ารหัสดิสก์และไฟล์ส่วนใหญ่ แม้ว่าจะมีการเข้ารหัส ด้วยฮาร์ดแวร์เฉพาะแทนที่จะเป็นซอฟต์แวร์ จัดการคีย์การเข้ารหัสดิบ

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

Android 11 จึงแก้ปัญหานี้ด้วยการรองรับคีย์ที่รวมไว้ในฮาร์ดแวร์เมื่ออุปกรณ์รองรับฮาร์ดแวร์ คีย์ที่รวมไว้ในฮาร์ดแวร์คือคีย์พื้นที่เก็บข้อมูลที่มีเฉพาะฮาร์ดแวร์เฉพาะเท่านั้นที่ทราบในรูปแบบไฟล์ดิบ ส่วนซอฟต์แวร์จะมองเห็นและทำงานกับคีย์เหล่านี้ในรูปแบบที่รวมไว้ (เข้ารหัส) เท่านั้น ฮาร์ดแวร์นี้ต้องสามารถสร้างและนำเข้าได้ คีย์พื้นที่เก็บข้อมูล การรวมคีย์พื้นที่เก็บข้อมูลในรูปแบบชั่วคราวและระยะยาว การรับค่า คีย์ย่อย ซึ่งจะเขียนโปรแกรมหนึ่งคีย์ย่อยลงในเครื่องมือคริปโตแบบอินไลน์โดยตรง และ การส่งคืนคีย์ย่อยที่แยกต่างหากไปยังซอฟต์แวร์

หมายเหตุ: เครื่องมือเข้ารหัสแบบอินไลน์ (หรือฮาร์ดแวร์การเข้ารหัสแบบอินไลน์) หมายถึงฮาร์ดแวร์ที่เข้ารหัส/ถอดรหัสข้อมูลขณะส่งไปยัง/จากอุปกรณ์เก็บข้อมูล โดยปกติแล้วจะเป็นโฮสต์ UFS หรือ eMMC ซึ่งใช้ส่วนขยายคริปโตที่กำหนดโดย ข้อมูลจำเพาะของ JEDEC

การออกแบบ

ส่วนนี้จะแสดงการออกแบบฟีเจอร์คีย์ที่รวมอยู่ในฮาร์ดแวร์ รวมถึงฮาร์ดแวร์ที่จำเป็นต้องใช้ การสนทนานี้มุ่งเน้นไปที่การเข้ารหัสตามไฟล์ (FBE) แต่ วิธีใช้โซลูชันกับข้อมูลเมตา การเข้ารหัสได้ด้วย

วิธีหนึ่งที่จะหลีกเลี่ยงการใช้คีย์การเข้ารหัสดิบในหน่วยความจำของระบบได้คือ ให้เก็บไว้เฉพาะในช่องคีย์ของเครื่องมือคริปโตแบบอินไลน์ อย่างไรก็ตาม วิธีการนี้อาจพบปัญหาบางอย่าง ดังนี้

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

เพื่อหลีกเลี่ยงปัญหาเหล่านี้ คีย์พื้นที่เก็บข้อมูลจะถูกสร้างเป็น คีย์ที่ห่อด้วยฮาร์ดแวร์ ซึ่งสามารถแยกและใช้งานได้โดย ฮาร์ดแวร์เฉพาะ ซึ่งทำให้รองรับคีย์ได้ไม่จำกัดจำนวน นอกจากนี้ ระบบจะแก้ไขลําดับชั้นของคีย์และย้ายบางส่วนไปยังฮาร์ดแวร์นี้ ซึ่งจะช่วยให้ส่งคีย์ย่อยกลับไปที่ซอฟต์แวร์สําหรับงานที่ไม่สามารถใช้เครื่องมือเข้ารหัสแบบอินไลน์ได้

ลําดับชั้นของคีย์

คีย์อาจดึงมาจากคีย์อื่นๆ โดยใช้ KDF (ฟังก์ชันคีย์ดึง) เช่น HKDF, ส่งผลให้เกิดลำดับชั้นคีย์

แผนภาพต่อไปนี้แสดงลำดับชั้นคีย์ทั่วไปสำหรับ FBE ระบบจะไม่ใช้คีย์ที่ปกปิดด้วยฮาร์ดแวร์ในกรณีต่อไปนี้

ลำดับชั้นคีย์ FBE (มาตรฐาน)
รูปที่ 1 ลําดับชั้นคีย์ FBE (มาตรฐาน)

คีย์คลาส FBE คือคีย์การเข้ารหัสดิบที่ Android ส่งไปยัง Linux เคอร์เนลเพื่อปลดล็อกชุดไดเรกทอรีที่เข้ารหัสโดยเฉพาะ เช่น ที่เก็บข้อมูลที่เข้ารหัสข้อมูลเข้าสู่ระบบสำหรับผู้ใช้ Android บางราย (ในเคอร์เนล คีย์นี้เรียกว่าคีย์หลัก fscrypt) จากคีย์นี้ เคอร์เนลจะสร้างคีย์ย่อยต่อไปนี้

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

ในทางตรงกันข้าม แผนภาพต่อไปนี้แสดงลำดับชั้นคีย์สำหรับ FBE คีย์ที่ห่อด้วยฮาร์ดแวร์จะใช้ในข้อใด

ลำดับชั้นคีย์ FBE (พร้อมคีย์ที่ห่อด้วยฮาร์ดแวร์)
รูปที่ 2 ลําดับชั้นของคีย์ FBE (มีคีย์ที่รวมไว้ในฮาร์ดแวร์)

เมื่อเทียบกับกรณีก่อนหน้านี้ จะมีการเพิ่มลําดับชั้นอีกระดับลงในลําดับชั้นคีย์ และย้ายคีย์การเข้ารหัสเนื้อหาไฟล์ โหนดรูทจะยังคงแสดงคีย์ที่ Android ส่งไปยัง Linux เพื่อปลดล็อกชุดไดเรกทอรีที่เข้ารหัส แต่ตอนนี้คีย์ดังกล่าวอยู่ในรูปแบบที่รวมไว้ชั่วคราว และจะต้องส่งไปยังฮาร์ดแวร์เฉพาะจึงจะใช้ได้ ฮาร์ดแวร์นี้ต้องใช้อินเทอร์เฟซ 2 รายการที่ใช้คีย์ที่รวมไว้ชั่วคราว ดังนี้

  • อินเทอร์เฟซเดียวสำหรับดึงข้อมูล inline_encryption_key โดยตรง วางโปรแกรมไว้ในช่องคีย์ของเครื่องมือคริปโตแบบอินไลน์ การดำเนินการนี้ช่วยให้ไฟล์ เนื้อหาที่จะเข้ารหัส/ถอดรหัสโดยที่ซอฟต์แวร์ไม่สามารถเข้าถึงไฟล์ข้อมูล RAW ในเคอร์เนลทั่วไปของ 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 ยังคงต้องจัดเก็บเวอร์ชันที่เข้ารหัสได้ บนดิสก์เพื่อให้ปลดล็อกได้ตั้งแต่แรก ในกรณีนี้ คุณสามารถใช้คีย์ดิบได้ อย่างไรก็ตาม คุณไม่ควรเก็บคีย์ดิบไว้ในหน่วยความจำของระบบเลย เพื่อไม่ให้มีการนำคีย์ดิบไปใช้นอกอุปกรณ์ แม้ว่าจะดึงข้อมูลคีย์ดิบออกเมื่อทำการบูตก็ตาม ด้วยเหตุนี้ แนวคิด ของการ Wrapper โฆษณาระยะยาว

ในการรองรับการจัดการคีย์ที่รวมอยู่ในทั้งสองวิธีนี้ ฮาร์ดแวร์จะต้อง ใช้อินเทอร์เฟซต่อไปนี้

  • อินเทอร์เฟซสำหรับสร้างและนำเข้าคีย์พื้นที่เก็บข้อมูล แล้วแสดงผลคีย์ดังกล่าว รูปแบบห่อหุ้มระยะยาว อินเทอร์เฟซเหล่านี้เข้าถึงได้แบบอ้อมผ่าน KeyMint และสอดคล้องกับTAG_STORAGE_KEYแท็ก KeyMint "สร้าง" vold ใช้ความสามารถนี้เพื่อสร้างพื้นที่เก็บข้อมูลใหม่ สำหรับใช้งานโดย 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 และการเข้ารหัสข้อมูลเมตา