مفاتيح الأجهزة

كما هو الحال مع معظم برامج تشفير الأقراص والملفات، يعتمد تشفير مساحة التخزين في Android عادةً على توفّر مفاتيح التشفير الأولية في ذاكرة النظام حتى يمكن إجراء عملية التشفير. حتى عندما يتم التشفير بواسطة أجهزة مخصصة بدلاً من البرامج، تظل البرامج بحاجة بشكل عام إلى إدارة مفاتيح التشفير الأولية.

لا يُعدّ ذلك عادةً مشكلة لأنّ المفاتيح لا تكون متوفّرة أثناء الهجوم بلا إنترنت، وهو النوع الرئيسي من الهجمات التي يهدف تشفير التخزين إلى الحماية منها. ومع ذلك، هناك رغبة في توفير حماية أكبر ضد أنواع أخرى من الهجمات، مثل هجمات إعادة التشغيل البارد والهجمات على الإنترنت التي قد يتمكّن فيها المهاجم من تسريب ذاكرة النظام بدون اختراق الجهاز بالكامل.

لحلّ هذه المشكلة، أتاح نظام التشغيل Android 11 إمكانية استخدام المفاتيح المحمية بالأجهزة في حال توفّر دعم الأجهزة. المفاتيح المحمية بواسطة أجهزة هي مفاتيح تخزين لا تعرفها الأجهزة المخصصة إلا في شكلها الأولي، ولا ترى البرامج هذه المفاتيح ولا تعمل بها إلا في شكلها المحمي (المشفّر). يجب أن يكون هذا الجهاز قادرًا على إنشاء مفاتيح تخزين واستيرادها، وتغليف مفاتيح التخزين في أشكال مؤقتة وطويلة الأمد، واشتقاق مفاتيح فرعية، وبرمجة مفتاح فرعي واحد مباشرةً في محرك تشفير مضمّن، وإرجاع مفتاح فرعي منفصل إلى البرنامج.

ملاحظة: يشير محرك التشفير المضمّن (أو أداة تشفير مضمّنة) إلى أداة تشفّر البيانات أو تفك تشفيرها أثناء انتقالها من جهاز التخزين أو إليه. عادةً ما يكون هذا مضيف UFS أو وحدة تحكّم eMMC تنفّذ امتدادات التشفير المحدّدة بمواصفات JEDEC ذات الصلة.

التصميم

يعرض هذا القسم تصميم ميزة المفاتيح المحمية بواسطة الأجهزة، بما في ذلك متطلبات توافق الأجهزة معها. تركّز هذه المناقشة على التشفير على مستوى الملفات (FBE)، ولكن ينطبق الحل أيضًا على تشفير البيانات الوصفية.

إحدى طرق تجنُّب الحاجة إلى مفاتيح التشفير الأولية في ذاكرة النظام هي الاحتفاظ بها فقط في فتحات المفاتيح الخاصة بمحرّك التشفير المضمّن. ومع ذلك، تواجه هذه الطريقة بعض المشاكل:

  • قد يتجاوز عدد مفاتيح التشفير عدد فتحات المفاتيح.
  • عادةً ما تفقد محرّكات التشفير المضمّنة محتوى فتحات المفاتيح إذا تمت إعادة ضبط وحدة التحكّم في مضيف التخزين. إعادة ضبط وحدة التحكّم في مضيف مساحة التخزين هي إجراء عادي لاسترداد البيانات من الأخطاء يتم تنفيذه في حال حدوث أنواع معيّنة من أخطاء مساحة التخزين، ويمكن أن تحدث هذه الأخطاء في أي وقت. لذلك، عند استخدام التشفير المضمّن، يجب أن يكون نظام التشغيل جاهزًا دائمًا لإعادة برمجة خانات المفاتيح بدون تدخل المستخدم.
  • لا يمكن استخدام محرّكات التشفير المضمّنة إلا لتشفير/فك تشفير كتل كاملة من البيانات على القرص. ومع ذلك، في حالة التشفير المستند إلى الملفات، يظل البرنامج بحاجة إلى تنفيذ عمليات تشفير أخرى، مثل تشفير أسماء الملفات واستخلاص معرّفات المفاتيح. سيظل البرنامج بحاجة إلى الوصول إلى مفاتيح التشفير المستند إلى الملفات الأولية لإجراء هذه المهام الأخرى.

لتجنُّب هذه المشاكل، يتم بدلاً من ذلك تحويل مفاتيح التخزين إلى مفاتيح محمية بواسطة أجهزة، ولا يمكن فك تشفيرها واستخدامها إلا من خلال أجهزة مخصّصة. يتيح ذلك إمكانية استخدام عدد غير محدود من المفاتيح. بالإضافة إلى ذلك، يتم تعديل التسلسل الهرمي للمفاتيح ونقله جزئيًا إلى هذا الجهاز، ما يتيح إرجاع مفتاح فرعي إلى البرنامج لتنفيذ المهام التي لا يمكنها استخدام محرك تشفير مضمّن.

التدرّج الهرمي للمفاتيح

يمكن اشتقاق المفاتيح من مفاتيح أخرى باستخدام دالة اشتقاق المفاتيح (KDF)، مثل HKDF، ما يؤدي إلى تسلسل هرمي للمفاتيح.

يوضّح المخطّط التالي التسلسل الهرمي النموذجي للمفاتيح في ميزة "التشفير المستند إلى الملفات" عند عدم استخدام المفاتيح المحمية بواسطة الأجهزة:

التسلسل الهرمي لمفاتيح التشفير المستند إلى الملفات (الإعداد التلقائي)
الشكل 1. التسلسل الهرمي لمفاتيح التشفير المستند إلى الملفات (FBE) (المعيار)

مفتاح فئة FBE هو مفتاح التشفير الأوّلي الذي يمرّره نظام التشغيل Android إلى نواة Linux لفتح مجموعة معيّنة من الدلائل المشفّرة، مثل مساحة التخزين المشفّرة ببيانات الاعتماد لمستخدم Android معيّن. (في النواة، يُطلق على هذا المفتاح اسم مفتاح رئيسي fscrypt). يستمد النواة من هذا المفتاح المفاتيح الفرعية التالية:

  • معرّف المفتاح لا يتم استخدام هذا المعرّف للتشفير، بل هو قيمة تُستخدَم لتحديد المفتاح الذي يتم من خلاله حماية ملف أو دليل معيّن.
  • مفتاح تشفير محتوى الملف
  • مفتاح تشفير أسماء الملفات

في المقابل، يوضّح المخطّط التالي تسلسل المفاتيح في ميزة "التشفير الكامل للجهاز" عند استخدام مفاتيح مضمّنة في الأجهزة:

التسلسل الهرمي لمفاتيح FBE (مع مفتاح ملفوف بالأجهزة)
الشكل 2. التسلسل الهرمي لمفاتيح FBE (مع مفتاح ملفوف بالأجهزة)

مقارنةً بالحالة السابقة، تمت إضافة مستوى إضافي إلى التسلسل الهرمي للمفتاح، وتمت إعادة تحديد موقع مفتاح تشفير محتوى الملف. لا تزال عقدة الجذر تمثّل المفتاح الذي يمرّره نظام التشغيل Android إلى Linux لفتح مجموعة من الأدلة المشفّرة. ومع ذلك، أصبح المفتاح الآن في شكل ملف مؤقت، ويجب تمريره إلى جهاز مخصّص لاستخدامه. يجب أن يتضمّن هذا الجهاز واجهتَين تستخدمان مفتاحًا مؤقتًا:

  • واجهة واحدة لاشتقاق inline_encryption_key وبرمجته مباشرةً في فتحة مفاتيح لمحرك التشفير المضمّن يتيح ذلك تشفير/فك تشفير محتوى الملفات بدون أن تتمكّن البرامج من الوصول إلى مفتاح التشفير الأولي. في نواة Android الشائعة، تتوافق هذه الواجهة مع العملية blk_crypto_ll_ops::keyslot_program، التي يجب أن ينفّذها برنامج تشغيل وحدة التخزين.
  • واجهة واحدة لاشتقاق sw_secret وعرضه ("software secret"، ويُعرف أيضًا باسم "السر الخام" في بعض المواضع)، وهو المفتاح الذي يستخدمه نظام التشغيل Linux لاشتقاق المفاتيح الفرعية لكل شيء باستثناء تشفير محتوى الملفات. في نواة Android الشائعة، تتوافق هذه الواجهة مع العملية blk_crypto_ll_ops::derive_sw_secret، التي يجب أن ينفّذها برنامج تشغيل وحدة التخزين.

لاستخراج inline_encryption_key وsw_secret من مفتاح التخزين الأوّلي، يجب أن يستخدم الجهاز وظيفة KDF قوية من ناحية التشفير. يجب أن تتّبع وظيفة اشتقاق المفتاح هذه أفضل ممارسات التشفير، ويجب أن تتضمّن قوة أمان لا تقل عن 256 بت، أي ما يكفي لأي خوارزمية مستخدَمة لاحقًا. ويجب أيضًا استخدام تصنيف وسياق مميّزَين عند استخلاص كل نوع من المفاتيح الفرعية لضمان عزل المفاتيح الفرعية الناتجة تشفيرًا، أي ألّا يؤدي معرفة أحدها إلى الكشف عن أي مفتاح فرعي آخر. لا يلزم تمديد المفتاح، لأنّ مفتاح التخزين الأولي هو مفتاح عشوائي موحّد.

من الناحية الفنية، يمكن استخدام أي دالة KDF تستوفي متطلبات الأمان. ومع ذلك، لأغراض الاختبار، تنفّذ vts_kernel_encryption_test وظيفة اشتقاق المفتاح نفسها في البرنامج لإعادة إنتاج النص المشفّر على القرص والتأكّد من صحته. لتسهيل الاختبار وضمان استخدام دالة KDF آمنة تمت مراجعتها من قبل، ننصح الأجهزة بتنفيذ دالة KDF التلقائية التي يتحقّق منها الاختبار. بالنسبة إلى الأجهزة التي تستخدم دالة 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 مع متجهات تهيئة عشوائية.

يجب إجراء تغييرات على البرنامج

يتضمّن 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) بسبب عدم رصد إمكانية استخدام المفاتيح المحمية بواسطة الأجهزة، لأنّ نتائج الاختبار تظل "ناجحة" في هذه الحالة.

بشكلٍ تلقائي، يفترض vts_kernel_encryption_test أنّ الجهاز ينفّذ وظيفة اشتقاق مفتاح (KDF) تُسمى kdf1. تنتمي وظيفة اشتقاق المفاتيح (KDF) هذه إلى مجموعة وظائف اشتقاق المفاتيح (KDF) في وضع العداد من NIST SP 800-108، وتستخدم AES-256-CMAC كدالة عشوائية زائفة. لمزيد من المعلومات حول CMAC، يُرجى الاطّلاع على مواصفات CMAC. تستخدِم وظيفة اشتقاق المفاتيح سياقات وتصنيفات محدّدة عند اشتقاق كل مفتاح فرعي. يجب أن تنفّذ الأجهزة هذه الدالة، بما في ذلك الاختيار الدقيق للسياق والتصنيف وتنسيق سلسلة الإدخال الثابتة عند اشتقاق كل مفتاح فرعي.

ومع ذلك، تنفّذ vts_kernel_encryption_test أيضًا وظائف KDF إضافية kdf2 من خلال kdf4. وهي آمنة تمامًا مثل kdf1 ولا تختلف إلا في اختيار السياقات والتصنيفات وتنسيق سلسلة الإدخال الثابتة. وهي متوفّرة فقط لتتوافق مع الأجهزة المختلفة.

بالنسبة إلى الأجهزة التي تستخدم دالة KDF مختلفة، اضبط السمة ro.crypto.hw_wrapped_keys.kdf في PRODUCT_VENDOR_PROPERTIES على اسم دالة KDF كما هو محدّد في رمز المصدر للاختبار. يؤدي ذلك إلى أن يبحث vts_kernel_encryption_test عن KDF بدلاً من kdf1. على سبيل المثال، لاختيار kdf2، استخدِم:

PRODUCT_VENDOR_PROPERTIES += ro.crypto.hw_wrapped_keys.kdf=kdf2

بالنسبة إلى الأجهزة التي تستخدم دالة اشتقاق مفتاح لا يتوافق مع الاختبار، أضِف أيضًا تنفيذًا لدالة اشتقاق المفتاح هذه إلى الاختبار وأعطِها اسمًا فريدًا.

تفعيل المفاتيح الملتفة

عندما يعمل دعم مفتاح التشفير المضمّن في الجهاز بشكل صحيح، عليك إجراء التغييرات التالية على ملف fstab الخاص بالجهاز لكي يستخدمه نظام Android في التشفير المستند إلى الملفات وتشفير البيانات الوصفية:

  • FBE: أضِف العلامة wrappedkey_v0 إلى المَعلمة fileencryption. على سبيل المثال، استخدِم fileencryption=::inlinecrypt_optimized+wrappedkey_v0. لمزيد من التفاصيل، يُرجى الاطّلاع على مستندات FBE.
  • تشفير البيانات الوصفية: أضِف العلامة wrappedkey_v0 إلى المَعلمة metadata_encryption. على سبيل المثال، استخدِم metadata_encryption=:wrappedkey_v0. لمزيد من التفاصيل، راجِع مستندات تشفير البيانات الوصفية.