مثل معظم برامج تشفير الأقراص والملفات، يعتمد تشفير مساحة التخزين في Android بشكل تقليدي على مفاتيح التشفير الأولية المتوفّرة في ذاكرة النظام لكي يتم تنفيذ التشفير. حتى في حال تنفيذ التشفير باستخدام أجهزة مخصّصة بدلاً من البرامج، لا يزال على البرامج بشكل عام إدارة مفاتيح التشفير الأولية.
لا يُعتبَر ذلك عادةً مشكلة لأنّ المفاتيح لن تكون متوفّرة أثناء هجوم بلا إنترنت، وهو النوع الرئيسي من الهجمات التي يهدف تشفير التخزين إلى حمايتك منها. ومع ذلك، هناك رغبة في توفير حماية مُحسنة ضد أنواع أخرى من الهجمات، مثل هجمات التشغيل البارد، والهجمات على الإنترنت التي قد يتمكّن فيها المهاجم من تسريب ملف ذاكرة النظام بدون اختراق الجهاز بالكامل.
لحلّ هذه المشكلة، وفّر نظام التشغيل Android 11 مفتاح تشفير مُدمج في الجهاز، وذلك في الأجهزة التي تتوفّر فيها هذه الميزة. مفاتيح الأجهزة المُغلفة هي مفاتيح تخزين لا يمكن الاطّلاع عليها إلا في شكلها الأصلي باستخدام الأجهزة المخصّصة، ولا يمكن للبرامج الاطّلاع على هذه المفاتيح والتعامل معها إلا في شكلها المغلف (المشفَّر). يجب أن تكون هذه الأجهزة قادرة على إنشاء مفاتيح التخزين واستيرادها، وتغليف مفاتيح التخزين بأشكال مؤقتة وطويلة المدى، واستخراج مفاتيح فرعية، وبرمجة مفتاح فرعي واحد مباشرةً في محرّك تشفير مضمّن، وتقديم مفتاح فرعي منفصل إلى البرنامج.
ملاحظة: يشير محرك التشفير المضمّن (أو أجهزة التشفير المضمّنة ) إلى الأجهزة التي تُشفِّر البيانات أو تُفكّ تشفيرها أثناء نقلها إلى جهاز التخزين أو من جهاز التخزين. وهي عادةً وحدة تحكم مضيف UFS أو eMMC تنفّذ إضافات التشفير المحددة من خلال مواصفات JEDEC المقابلة لها.
التصميم
يعرض هذا القسم تصميم ميزة مفاتيح التشفير المُدارة بالأجهزة، بما في ذلك متطلبات التوافق مع الأجهزة. تركّز هذه المناقشة على التشفير على مستوى الملفات (FBE)، ولكن ينطبق الحلّ أيضًا على تشفير البيانات الوصفية.
إحدى الطرق لتجنُّب الحاجة إلى مفاتيح التشفير الأوّلية في ذاكرة النظام هي الاحتفاظ بها فقط في خانات المفاتيح الخاصة بمحرك التشفير المضمّن. ومع ذلك، يواجه هذا الأسلوب بعض المشاكل:
- قد يتجاوز عدد مفاتيح التشفير عدد مفاتيح التشفير.
- تفقد عادةً محركات التشفير المضمّنة محتوى خانات المفاتيح الخاصة بها في حال إعادة ضبط وحدة التحكّم في مساحة التخزين (عادةً UFS أو eMMC). إنّ إعادة ضبط وحدة التحكّم في مساحة التخزين هي إجراء عادي لاسترداد الأخطاء يتم تنفيذه في حال حدوث أنواع معيّنة من أخطاء مساحة التخزين، ويمكن أن تحدث هذه الأخطاء في أي وقت. لذلك، عند استخدام التشفير المضمّن، يجب أن يكون نظام التشغيل جاهزًا دائمًا لإعادة برمجة خانات المفاتيح بدون تدخل المستخدم.
- لا يمكن استخدام محرّكات التشفير المضمّنة إلا لتشفير/فك تشفير مجموعات كاملة من البيانات على القرص. في المقابل، في حال استخدام FBE، يجب أن يكون البرامج بحاجة إلى إمكانية تنفيذ أعمال تشفير أخرى، مثل تشفير أسماء الملفات واشتقاق معرّفات المفاتيح. سيظلّ على البرنامج الوصول إلى مفاتيح FBE الأوّلية لكي تتمكّن من تنفيذ هذه المهام الأخرى.
لتجنُّب هذه المشاكل، يتم تحويل مفاتيح التخزين بدلاً من ذلك إلى مفاتيح مُغلفة بالأجهزة، ولا يمكن إزالة الغلاف واستخدامها إلا باستخدام أجهزة مخصّصة. يتيح ذلك استخدام عدد غير محدود من المفاتيح. بالإضافة إلى ذلك، يتم تعديل التسلسل الهرمي للمفتاح ونقله جزئيًا إلى هذا الجهاز، مما يسمح بإرجاع مفتاح فرعي إلى البرنامج للمهام التي لا يمكنها استخدام محرك تشفير مضمّن.
التدرّج الهرمي الرئيسي
يمكن اشتقاق المفاتيح من مفاتيح أخرى باستخدام دالة اشتقاق المفاتيح (KDF)، مثل HKDF، مما يؤدي إلى إنشاء تسلسل هرمي للمفاتيح.
يوضّح الرسم البياني التالي التسلسل الهرمي المعتاد للمفاتيح في ميزة "التشفير من جهة العميل" عندمالا يتم استخدام مفاتيح مُغلفة بالأجهزة:
مفتاح فئة FBE هو مفتاح التشفير الأوّلي الذي يمرره Android إلى ملف Linux kernel لفتح قفل مجموعة معيّنة من الدلائل المشفّرة، مثل مساحة التخزين المشفّرة باستخدام بيانات الاعتماد لمستخدم معيّن على Android. (يُعرف هذا المفتاح في النواة باسم مفتاح fscrypt الرئيسي). تستخرج النواة من هذا المفتاح المفاتيح الفرعية التالية:
- معرِّف المفتاح. لا يتم استخدام هذا المفتاح للتشفير، بل هو قيمة تُستخدَم لتحديد المفتاح الذي يتم حماية ملف أو دليل معيّن به.
- مفتاح تشفير محتوى الملف
- مفتاح تشفير أسماء الملفات
في المقابل، يوضِّح المخطّط التالي التسلسل الهرمي للمفاتيح في ميزة "التشفير من جهة العميل" عند استخدام مفاتيح مُغلفة بالأجهزة:
مقارنةً بالحالة السابقة، تمت إضافة مستوى إضافي إلى التسلسل الهرمي للمفتاح ، وتم نقل مفتاح تشفير محتوى الملف. وتظل العقدة الجذرية تمثل المفتاح الذي يمرره 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 واحدة وتنفيذها، ويمكن العثور عليها
في رمز المصدر لـ vts_kernel_encryption_test
.
يُنصح بأن تستخدم الأجهزة دالة KDF هذه التي تستخدم NIST SP 800-108 "KDF في وضع العداد" مع AES-256-CMAC كآلية معالجة الطلبات. ملاحظة: لكي تكون متوافقة، يجب أن تكون جميع أجزاء الخوارزمية متطابقة، بما في ذلك اختيار سياقات 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
) بسبب عدم رصد توافق
المفاتيح المغلفة بالأجهزة، لأنّ نتائج الاختبار لا تزال "تم اجتيازها" في هذه الحالة.
تفعيل المفاتيح
عندما تعمل ميزة دعم المفتاح ملفوف الجهاز بشكل صحيح، يمكنك إجراء التغييرات التالية على ملف fstab
الخاص بالجهاز لجعل Android يستخدمه في FBE وتشفير البيانات الوصفية:
- FBE: أضِف العلامة
wrappedkey_v0
إلى المَعلمةfileencryption
. على سبيل المثال، استخدِم السمةfileencryption=::inlinecrypt_optimized+wrappedkey_v0
. لمزيد من التفاصيل، يُرجى الاطّلاع على مستندات FBE. - تشفير البيانات الوصفية: أضِف علامة
wrappedkey_v0
إلى مَعلمةmetadata_encryption
. على سبيل المثال، يمكنك استخدامmetadata_encryption=:wrappedkey_v0
. لمزيد من التفاصيل، راجِع مستندات تشفير البيانات الوصفية.