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

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

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

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

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

डिज़ाइन

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

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

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

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

पासकोड की हैरारकी

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

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

एफ़बीई पासकोड की हैरारकी (स्टैंडर्ड)
पहली इमेज. एफ़बीई पासकोड की हैरारकी (स्टैंडर्ड)

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

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

पासकोड को रैप करना

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

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

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

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

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

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

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

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

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

हालांकि, लागू करने के तरीके के हिसाब से कुछ बदलाव करने होंगे.

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_keyslot_manager::features में BLK_CRYPTO_FEATURE_WRAPPED_KEYS सेट करें, blk_ksm_ll_ops::keyslot_program और blk_ksm_ll_ops::keyslot_evict को हार्डवेयर में सुरक्षित की गई कुंजियों को प्रोग्राम करने/हटाने की सुविधा दें, और blk_ksm_ll_ops::derive_raw_secret लागू करें.

android11 कर्नेल के लिए, keyslot_manager::features में BLK_CRYPTO_FEATURE_WRAPPED_KEYS सेट करें. साथ ही, 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 के KDFs के काउंटर मोड फ़ैमिली से जुड़ा है. साथ ही, यह AES-256-CMAC का इस्तेमाल, सूडोरैंडम फ़ंक्शन के तौर पर करता है. CMAC के बारे में ज़्यादा जानकारी के लिए, CMAC के लिए स्पेसिफ़िकेशन देखें. हर सब-की जनरेट करते समय, केडीएफ़ खास कॉन्टेक्स्ट और लेबल का इस्तेमाल करता है. हार्डवेयर को यह केडीएफ़ लागू करना चाहिए. इसमें हर सब-की जनरेट करते समय, कॉन्टेक्स्ट, लेबल, और तय इनपुट स्ट्रिंग के फ़ॉर्मैट की सटीक पसंद शामिल होनी चाहिए.

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

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

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

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

रैप की सुविधा चालू करना

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