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

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

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

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

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

डिज़ाइन

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

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

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

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

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

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

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

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

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

तकनीकी तौर पर, सुरक्षा से जुड़ी ज़रूरी शर्तें पूरी करने वाले किसी भी केडीएफ़ का इस्तेमाल किया जा सकता है. हालांकि, जांच के मकसद से, टेस्ट कोड में उसी केडीएफ़ को फिर से लागू करना ज़रूरी है. फ़िलहाल, एक केडीएफ़ की समीक्षा हो चुकी है और उसे लागू कर दिया गया है. इसे vts_kernel_encryption_test के सोर्स कोड में देखा जा सकता है. हमारा सुझाव है कि हार्डवेयर इस केडीएफ़ का इस्तेमाल करे. यह केडीएफ़, NIST SP 800-108 "काउंटर मोड में केडीएफ़" का इस्तेमाल करता है. साथ ही, इसमें पीआरएफ़ के तौर पर AES-256-CMAC का इस्तेमाल किया जाता है. ध्यान दें कि काम करने के लिए, एल्गोरिदम के सभी हिस्से एक जैसे होने चाहिए. इनमें हर सब-की के लिए, केडीएफ़ कॉन्टेक्स्ट और लेबल की पसंद भी शामिल है.

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

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

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

स्टोरेज को अनलॉक करने के लिए, 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) को, हार्डवेयर पर सेव की गई कुंजियों के लिए सहायता का पता न चलने की वजह से स्किप नहीं किया गया था. ऐसा इसलिए, क्योंकि उस मामले में टेस्ट के नतीजे अब भी "पास" हैं.

बटन चालू करना

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

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