हार्डवेयर से सुरक्षित की गई कुंजियां

ज़्यादातर डिस्क और फ़ाइल एन्क्रिप्शन सॉफ़्टवेयर की तरह, Android के स्टोरेज एन्क्रिप्शन में भी सिस्टम मेमोरी में रॉ एन्क्रिप्शन कुंजियों का इस्तेमाल किया जाता है. इससे एन्क्रिप्शन किया जा सकता है. जब एन्क्रिप्शन, सॉफ़्टवेयर के बजाय किसी खास हार्डवेयर की मदद से किया जाता है, तब भी सॉफ़्टवेयर को आम तौर पर रॉ एन्क्रिप्शन कुंजियों को मैनेज करना होता है.

आम तौर पर, इसे समस्या नहीं माना जाता. ऐसा इसलिए, क्योंकि ऑफ़लाइन अटैक के दौरान कुंजियां मौजूद नहीं होती हैं. यह मुख्य तरह का ऐसा अटैक है जिससे स्टोरेज को एन्क्रिप्ट (सुरक्षित) करने का मकसद होता है. हालांकि, अन्य तरह के हमलों से ज़्यादा सुरक्षा देने की ज़रूरत है. जैसे, कोल्ड बूट अटैक और ऑनलाइन हमले. इनमें हमलावर, डिवाइस को पूरी तरह से हैक किए बिना सिस्टम मेमोरी को लीक कर सकता है.

इस समस्या को हल करने के लिए, Android 11 में हार्डवेयर-रैप्ड कुंजियों के लिए सहायता उपलब्ध कराई गई है. यहां हार्डवेयर की सहायता उपलब्ध है. हार्डवेयर-रैप्ड कुंजियां, स्टोरेज कुंजियां होती हैं. ये सिर्फ़ हार्डवेयर को पता होती हैं. सॉफ़्टवेयर, इन कुंजियों को सिर्फ़ रैप्ड (एन्क्रिप्ट) फ़ॉर्म में देखता है और इनके साथ काम करता है. इस हार्डवेयर में, स्टोरेज कुंजियां जनरेट और इंपोर्ट करने की सुविधा होनी चाहिए. साथ ही, इसमें स्टोरेज कुंजियों को कुछ समय के लिए और लंबे समय तक इस्तेमाल करने के लिए रैप करने की सुविधा होनी चाहिए. इसके अलावा, इसमें सबकुंजियां पाने, एक सबकुंजी को सीधे तौर पर इनलाइन क्रिप्टो इंजन में प्रोग्राम करने, और सॉफ़्टवेयर को एक अलग सबकुंजी वापस भेजने की सुविधा होनी चाहिए.

ध्यान दें: इनलाइन क्रिप्टो इंजन या इनलाइन एन्क्रिप्शन हार्डवेयर, ऐसे हार्डवेयर को कहते हैं जो स्टोरेज डिवाइस से डेटा को एन्क्रिप्ट/डिक्रिप्ट करता है. आम तौर पर, यह UFS या eMMC होस्ट कंट्रोलर होता है. यह JEDEC के संबंधित स्पेसिफ़िकेशन में तय किए गए क्रिप्टो एक्सटेंशन लागू करता है.

डिज़ाइन

इस सेक्शन में, हार्डवेयर-रैप्ड कुंजियों की सुविधा के डिज़ाइन के बारे में बताया गया है. इसमें यह भी बताया गया है कि इसके लिए किस तरह के हार्डवेयर की ज़रूरत होती है. इस चर्चा में अलग-अलग फ़ाइलों को अलग-अलग तरीकों से एन्क्रिप्ट करने के तरीके (एफ़बीई) पर फ़ोकस किया गया है. हालांकि, यह समाधान मेटाडेटा एन्क्रिप्शन पर भी लागू होता है.

सिस्टम मेमोरी में रॉ एन्क्रिप्शन कुंजियों को रखने से बचने का एक तरीका यह है कि उन्हें सिर्फ़ इनलाइन क्रिप्टो इंजन के कीस्लॉट में रखा जाए. हालांकि, इस तरीके में कुछ समस्याएं आती हैं:

  • ऐसा हो सकता है कि एन्क्रिप्शन कुंजियों की संख्या, कीस्लॉट की संख्या से ज़्यादा हो.
  • आम तौर पर, स्टोरेज होस्ट कंट्रोलर को रीसेट करने पर, इनलाइन क्रिप्टो इंजन के कीस्लॉट का कॉन्टेंट मिट जाता है. स्टोरेज होस्ट कंट्रोलर को रीसेट करना, गड़बड़ी ठीक करने की एक सामान्य प्रक्रिया है. यह प्रक्रिया तब लागू होती है, जब स्टोरेज से जुड़ी कुछ गड़बड़ियां होती हैं. ऐसी गड़बड़ियां कभी भी हो सकती हैं. इसलिए, जब इनलाइन क्रिप्टो का इस्तेमाल किया जा रहा हो, तो ऑपरेटिंग सिस्टम को हमेशा उपयोगकर्ता के हस्तक्षेप के बिना, कीस्लॉट को फिर से प्रोग्राम करने के लिए तैयार रहना चाहिए.
  • इनलाइन क्रिप्टो इंजन का इस्तेमाल सिर्फ़ डिस्क पर मौजूद डेटा के पूरे ब्लॉक को एन्क्रिप्ट (सुरक्षित) या डिक्रिप्ट (सुरक्षित तरीके से बदलना) करने के लिए किया जा सकता है. हालांकि, FBE के मामले में सॉफ़्टवेयर को अब भी अन्य क्रिप्टोग्राफ़िक काम करने की ज़रूरत होती है. जैसे, फ़ाइल नामों को एन्क्रिप्ट (सुरक्षित) करना और कुंजी आइडेंटिफ़ायर हासिल करना. हालांकि, इस तरह के अन्य कामों के लिए, सॉफ़्टवेयर को अब भी रॉ FBE कुंजियों का ऐक्सेस चाहिए होगा.

इन समस्याओं से बचने के लिए, स्टोरेज कुंजियों को हार्डवेयर-रैप्ड कुंजियों में बदल दिया जाता है. इन्हें सिर्फ़ खास हार्डवेयर से अनरैप किया जा सकता है और इस्तेमाल किया जा सकता है. इससे, जितनी चाहें उतनी कुंजियों का इस्तेमाल किया जा सकता है. इसके अलावा, कुंजी के क्रम में बदलाव किया गया है और इसे कुछ हद तक इस हार्डवेयर में ले जाया गया है. इससे सॉफ़्टवेयर को सबकुंजी वापस मिल जाती है. ऐसा उन कामों के लिए किया जाता है जिनमें इनलाइन क्रिप्टो इंजन का इस्तेमाल नहीं किया जा सकता.

कुंजी हैरारकी

की डेरिवाइशन फ़ंक्शन (केडीएफ़), जैसे कि HKDF का इस्तेमाल करके, कुंजियों को दूसरी कुंजियों से बनाया जा सकता है. इससे कुंजी का क्रम बनता है.

यहां दिए गए डायग्राम में, FBE के लिए सामान्य की हैरारकी दिखाई गई है. इसमें हार्डवेयर-रैप्ड कुंजियों का इस्तेमाल नहीं किया गया है:

FBE की हैरारकी (स्टैंडर्ड)
पहली इमेज. FBE की हैरारकी (स्टैंडर्ड)

एफ़बीई क्लास की, एन्क्रिप्शन की रॉ की होती है. Android इसे Linux कर्नल को पास करता है, ताकि एन्क्रिप्ट की गई डायरेक्ट्री के किसी सेट को अनलॉक किया जा सके. जैसे, Android के किसी उपयोगकर्ता के लिए क्रेडेंशियल-एन्क्रिप्ट किया गया स्टोरेज. (कर्नेल में, इस कुंजी को fscrypt मास्टर कुंजी कहा जाता है.) इस कुंजी से, कर्नेल इन सब-कुंजियों को हासिल करता है:

  • कुंजी का आइडेंटिफ़ायर. इसका इस्तेमाल एन्क्रिप्शन के लिए नहीं किया जाता. इसके बजाय, यह एक ऐसी वैल्यू है जिसका इस्तेमाल उस कुंजी की पहचान करने के लिए किया जाता है जिससे किसी फ़ाइल या डायरेक्ट्री को सुरक्षित किया जाता है.
  • फ़ाइल के कॉन्टेंट को एन्क्रिप्ट (सुरक्षित) करने की कुंजी
  • फ़ाइल के नामों को एन्क्रिप्ट (सुरक्षित) करने के लिए इस्तेमाल की जाने वाली कुंजी

इसके उलट, इस डायग्राम में हार्डवेयर-रैप की गई कुंजियों का इस्तेमाल करने पर, FBE के लिए कुंजी हैरारकी दिखाई गई है:

एफ़बीई कुंजी का क्रम (हार्डवेयर-रैप की गई कुंजी के साथ)
दूसरी इमेज. 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 को क्रिप्टोग्राफ़ी के सबसे सही तरीकों का पालन करना चाहिए. इसमें कम से कम 256 बिट की सुरक्षा होनी चाहिए. यह बाद में इस्तेमाल किए जाने वाले किसी भी एल्गोरिदम के लिए काफ़ी है. साथ ही, हर तरह की सब-की जनरेट करते समय, इसे अलग लेबल और कॉन्टेक्स्ट का इस्तेमाल करना चाहिए. इससे यह पक्का किया जा सकेगा कि जनरेट की गई सब-की क्रिप्टोग्राफ़िक तौर पर अलग-अलग हैं. इसका मतलब है कि इनमें से किसी एक के बारे में जानकारी होने से, किसी दूसरी सब-की के बारे में पता नहीं चलेगा. कुंजी को बढ़ाने की ज़रूरत नहीं है, क्योंकि रॉ स्टोरेज कुंजी पहले से ही एक समान रूप से रैंडम कुंजी है.

तकनीकी तौर पर, सुरक्षा से जुड़ी ज़रूरी शर्तों को पूरा करने वाले किसी भी केडीएफ़ का इस्तेमाल किया जा सकता है. हालांकि, जांच के लिए vts_kernel_encryption_test, सॉफ़्टवेयर में उसी KDF को लागू करता है, ताकि डिस्क पर मौजूद सिफ़रटेक्स्ट को फिर से बनाया जा सके. साथ ही, यह पुष्टि की जा सके कि यह सही है. हमारा सुझाव है कि हार्डवेयर, डिफ़ॉल्ट KDF को लागू करे. इससे टेस्टिंग आसान हो जाएगी. साथ ही, यह पक्का किया जा सकेगा कि सुरक्षित और पहले से समीक्षा किया गया KDF इस्तेमाल किया जा रहा है. अगर हार्डवेयर में किसी दूसरे केडीएफ़ का इस्तेमाल किया जाता है, तो रैप की गई कुंजियों की जांच करना लेख पढ़ें. इसमें बताया गया है कि जांच को कैसे कॉन्फ़िगर किया जाए.

कुंजी को रैप करना

हार्डवेयर रैप की गई कुंजियों के सुरक्षा लक्ष्यों को पूरा करने के लिए, दो तरह की की रैपिंग तय की गई है:

  • एफ़ेमरल रैपिंग: हार्डवेयर, रॉ की को एक ऐसी कुंजी का इस्तेमाल करके एन्क्रिप्ट (सुरक्षित) करता है जो हर बूट पर किसी भी क्रम में जनरेट होती है. साथ ही, इसे सीधे तौर पर हार्डवेयर के बाहर नहीं दिखाया जाता.
  • लॉन्ग-टर्म रैपिंग: हार्डवेयर में मौजूद यूनीक और स्थायी कुंजी का इस्तेमाल करके, हार्डवेयर रॉ की को एन्क्रिप्ट (सुरक्षित) करता है. यह कुंजी, हार्डवेयर के बाहर सीधे तौर पर नहीं दिखती.

स्टोरेज को अनलॉक करने के लिए, Linux कर्नल को पास की गई सभी कुंजियों को कुछ समय के लिए रैप किया जाता है. इससे यह पक्का होता है कि अगर कोई हमलावर सिस्टम मेमोरी से इस्तेमाल की जा रही कुंजी को निकाल लेता है, तो वह कुंजी न सिर्फ़ डिवाइस से बाहर, बल्कि रीबूट के बाद डिवाइस पर भी इस्तेमाल नहीं की जा सकती.

साथ ही, Android को डिस्क पर कुंजियों का एन्क्रिप्ट (सुरक्षित) किया गया वर्शन सेव करना होगा, ताकि उन्हें अनलॉक किया जा सके. इसके लिए, रॉ डेटा की कुंजी काम करेगी. हालांकि, यह बेहतर है कि सिस्टम मेमोरी में कभी भी रॉ की मौजूद न हों, ताकि उन्हें कभी भी डिवाइस से बाहर इस्तेमाल करने के लिए न निकाला जा सके. भले ही, उन्हें बूट होने के समय निकाला गया हो. इस वजह से, लंबे समय तक रैपिंग करने की सुविधा को तय किया गया है.

इन दो अलग-अलग तरीकों से रैप की गई कुंजियों को मैनेज करने के लिए, हार्डवेयर को इन इंटरफ़ेस को लागू करना होगा:

  • स्टोरेज की कुंजियां जनरेट और इंपोर्ट करने के लिए इंटरफ़ेस. ये कुंजियां, लंबे समय तक इस्तेमाल की जा सकने वाली रैप की गई फ़ॉर्म में वापस भेज दी जाती हैं. इन इंटरफ़ेस को KeyMint के ज़रिए परोक्ष रूप से ऐक्सेस किया जाता है. ये TAG_STORAGE_KEY KeyMint टैग से जुड़े होते हैं. Android के लिए नई स्टोरेज कुंजियां जनरेट करने के लिए, vold "जनरेट करें" सुविधा का इस्तेमाल करता है. वहीं, टेस्ट कुंजियां इंपोर्ट करने के लिए, vts_kernel_encryption_test "इंपोर्ट करें" सुविधा का इस्तेमाल करता है.
  • यह इंटरफ़ेस, लंबे समय तक रैप की गई स्टोरेज कुंजी को कम समय के लिए रैप की गई स्टोरेज कुंजी में बदलने के लिए होता है. यह convertStorageKeyToEphemeral KeyMint तरीके से मेल खाता है. इस तरीके का इस्तेमाल vold और vts_kernel_encryption_test, दोनों ही स्टोरेज को अनलॉक करने के लिए करते हैं.

की रैपिंग एल्गोरिदम, लागू करने से जुड़ी जानकारी है. हालांकि, इसमें रैंडम IV के साथ AES-256-GCM जैसे मज़बूत एईएडी का इस्तेमाल किया जाना चाहिए.

सॉफ़्टवेयर में बदलाव करना ज़रूरी है

AOSP में, हार्डवेयर रैप की गई कुंजियों के साथ काम करने के लिए पहले से ही एक बुनियादी फ़्रेमवर्क मौजूद है. इसमें vold जैसे यूज़रस्पेस कॉम्पोनेंट के साथ-साथ, blk-crypto, fscrypt, और dm-default-key में Linux कर्नल के लिए सहायता शामिल है.

हालांकि, लागू करने से जुड़े कुछ बदलाव करने ज़रूरी हैं.

KeyMint में हुए बदलाव

डिवाइस के KeyMint को इस तरह से बदलना होगा कि वह TAG_STORAGE_KEY के साथ काम कर सके. साथ ही, convertStorageKeyToEphemeral तरीके को लागू किया जा सके.

Keymaster में, convertStorageKeyToEphemeral के बजाय exportKey का इस्तेमाल किया जाता था.

Linux कर्नेल में हुए बदलाव

डिवाइस के इनलाइन क्रिप्टो इंजन के लिए, Linux कर्नल ड्राइवर में बदलाव करना होगा, ताकि हार्डवेयर रैप की गई कुंजियों का इस्तेमाल किया जा सके.

android14 और इससे ऊपर के कर्नल के लिए, blk_crypto_profile::key_types_supported में BLK_CRYPTO_KEY_TYPE_HW_WRAPPED सेट करें, 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 यह मानता है कि हार्डवेयर, केडीएफ़ को लागू करता है. इसे kdf1 कहा जाता है. यह KDF, NIST SP 800-108 के काउंटर मोड फ़ैमिली से जुड़ा है. साथ ही, यह स्यूडोरैंडम फ़ंक्शन के तौर पर AES-256-CMAC का इस्तेमाल करता है. सीएमएसी के बारे में ज़्यादा जानकारी के लिए, सीएमएसी की खास बातें देखें. हर सबकुंजी को बनाते समय, KDF कुछ खास कॉन्टेक्स्ट और लेबल का इस्तेमाल करता है. हार्डवेयर को इस KDF को लागू करना चाहिए. इसमें हर सबकुंजी को हासिल करते समय, कॉन्टेक्स्ट, लेबल, और तय की गई इनपुट स्ट्रिंग के फ़ॉर्मैट का सटीक विकल्प शामिल होना चाहिए.

हालांकि, vts_kernel_encryption_test, kdf4 के ज़रिए अतिरिक्त KDF भी लागू करता है.kdf2 ये kdf1 जितने ही सुरक्षित हैं. इनमें सिर्फ़ कॉन्टेक्स्ट, लेबल, और तय की गई इनपुट स्ट्रिंग की फ़ॉर्मैटिंग का अंतर होता है. ये सिर्फ़ अलग-अलग हार्डवेयर के साथ काम करने के लिए बनाए जाते हैं.

ऐसे डिवाइसों के लिए जो किसी दूसरे KDF का इस्तेमाल करते हैं, ro.crypto.hw_wrapped_keys.kdf में ro.crypto.hw_wrapped_keys.kdf सिस्टम प्रॉपर्टी को KDF के नाम पर सेट करें. यह नाम, टेस्ट सोर्स कोड में तय किया गया है.PRODUCT_VENDOR_PROPERTIES इससे vts_kernel_encryption_test, kdf1 के बजाय उस KDF की जांच करता है. उदाहरण के लिए, kdf2 चुनने के लिए, इसका इस्तेमाल करें:

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

ऐसे डिवाइसों के लिए जो ऐसे KDF का इस्तेमाल करते हैं जिसे टेस्ट में इस्तेमाल नहीं किया जा सकता, टेस्ट में उस KDF को भी लागू करें और उसे कोई यूनीक नाम दें.

रैप की गई कुंजियां चालू करना

जब डिवाइस के हार्डवेयर-रैप्ड कुंजी का इस्तेमाल सही तरीके से किया जा रहा हो, तब डिवाइस की fstab फ़ाइल में ये बदलाव करें, ताकि Android इसका इस्तेमाल FBE और मेटाडेटा एन्क्रिप्शन के लिए कर सके:

  • FBE: wrappedkey_v0 पैरामीटर में wrappedkey_v0 फ़्लैग जोड़ें.fileencryption उदाहरण के लिए, fileencryption=::inlinecrypt_optimized+wrappedkey_v0 का इस्तेमाल करें. ज़्यादा जानकारी के लिए, FBE के दस्तावेज़ देखें.
  • मेटाडेटा एन्क्रिप्शन: metadata_encryption पैरामीटर में wrappedkey_v0 फ़्लैग जोड़ें. उदाहरण के लिए, metadata_encryption=:wrappedkey_v0 का इस्तेमाल करें. ज़्यादा जानकारी के लिए, मेटाडेटा के एन्क्रिप्शन से जुड़ा दस्तावेज़ देखें.