مفاتيح مغلَّفة بالأجهزة

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

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

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

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

التصميم

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

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

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

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

التدرّج الهرمي الرئيسي

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

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

التسلسل الهرمي لمفتاح FBE (عادي)
الشكل 1. التدرّج الهرمي لمفتاح FBE (عادي)

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

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

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

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

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

  • واجهة واحدة لاشتقاق inline_encryption_key بشكل مباشر برمجته على شكل مفتاح مضمّن في محرك التشفير المضمّن. سيؤدي هذا الإجراء إلى السماح بالملفات أن يتم تشفير المحتوى أو فك تشفيره دون أن يكون بإمكان البرامج الوصول إلى البيانات المفتاح. تتوافق هذه الواجهة في نواة Android الشائعة مع عملية blk_crypto_ll_ops::keyslot_program، التي يجب أن تكون التي تم تنفيذها بواسطة برنامج تشغيل التخزين.
  • واجهة واحدة لاشتقاق sw_secret وعرضه سر" -- يسمى أيضًا "السر الأولي" في بعض الأماكن)، وهو المفتاح الذي يستخدم نظام التشغيل Linux لاشتقاق المفاتيح الفرعية لكل شيء ما عدا محتويات الملف. تشفير البيانات. في نواة Android الشائعة، تتوافق هذه الواجهة مع عملية blk_crypto_ll_ops::derive_sw_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 على إطار عمل أساسي لدعم المفاتيح المغلفة بالأجهزة. هذا النمط الدعم في مكونات مساحة المستخدم، مثل vold، بالإضافة إلى دعم نواة Linux في blk-crypto وfscrypt مفتاح dm-default.

ومع ذلك، يجب إجراء بعض التغييرات الخاصة بعملية التنفيذ.

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