Android 4.4 और इसके बाद के वर्शन में, डिवाइस-मैपर-वैरिटी (dm-verity) कर्नेल की सुविधा के ज़रिए पुष्टि की सुविधा काम करती है. यह सुविधा ज़रूरी नहीं है. यह ब्लॉक डिवाइसों की पूरी सुरक्षा की जांच पारदर्शी तरीके से करती है. dm-verity की मदद से, ऐसे रूटकिट को रोका जा सकता है जो रूट की अनुमतियां हासिल करके डिवाइसों को नुकसान पहुंचा सकते हैं. इस सुविधा की मदद से, Android डिवाइसों के उपयोगकर्ता यह पक्का कर सकते हैं कि डिवाइस को चालू करने पर, वह उसी स्थिति में हो जिस स्थिति में उसे आखिरी बार इस्तेमाल किया गया था.
रूट की अनुमतियों वाले संभावित रूप से नुकसानदेह ऐप्लिकेशन (पीएचए), डिवाइस पर मौजूद होने के बावजूद, डिवाइस पर मौजूद होने का पता लगाने वाले प्रोग्राम से छिप सकते हैं. इसके अलावा, वे अपने असली नाम के बजाय कोई दूसरा नाम भी इस्तेमाल कर सकते हैं. रूटिंग सॉफ़्टवेयर ऐसा कर सकता है, क्योंकि आम तौर पर यह डिटेक्टर की तुलना में ज़्यादा खास होता है. इससे सॉफ़्टवेयर, डिटेक्शन प्रोग्राम को "झूठ" बोल सकता है.
dm-verity सुविधा की मदद से, फ़ाइल सिस्टम की स्टोरेज लेयर यानी ब्लॉक डिवाइस को देखा जा सकता है. साथ ही, यह भी पता लगाया जा सकता है कि यह अपने अनुमानित कॉन्फ़िगरेशन से मेल खाता है या नहीं. यह क्रिप्टोग्राफ़िक हैश ट्री का इस्तेमाल करके ऐसा करता है. हर ब्लॉक (आम तौर पर 4K) के लिए, SHA256 हैश होता है.
हैश वैल्यू, पेजों के ट्री में सेव की जाती हैं. इसलिए, बाकी ट्री की पुष्टि करने के लिए, सिर्फ़ टॉप-लेवल "रूट" हैश पर भरोसा किया जाना चाहिए. किसी भी ब्लॉक में बदलाव करने का मतलब है कि क्रिप्टोग्राफ़िक हैश को तोड़ दिया गया है. इस स्ट्रक्चर के बारे में जानने के लिए, नीचे दिया गया डायग्राम देखें.

पहली इमेज. dm-verity हैश टेबल
बूट पार्टीशन में एक सार्वजनिक पासकोड शामिल होता है. डिवाइस बनाने वाली कंपनी को इसकी पुष्टि बाहर से करनी होती है. उस कुंजी का इस्तेमाल, हैश के हस्ताक्षर की पुष्टि करने के लिए किया जाता है. साथ ही, यह पुष्टि करने के लिए भी किया जाता है कि डिवाइस का सिस्टम पार्टीशन सुरक्षित है और उसमें कोई बदलाव नहीं हुआ है.
कार्रवाई
dm-verity सुरक्षा, कर्नेल में मौजूद होती है. इसलिए, अगर रूट करने वाला सॉफ़्टवेयर, कोर से पहले सिस्टम को हैक कर लेता है, तो वह उस ऐक्सेस को बनाए रखता है. इस जोखिम को कम करने के लिए, ज़्यादातर मैन्युफ़ैक्चरर डिवाइस में पहले से मौजूद कुंजी का इस्तेमाल करके, कर्नेल की पुष्टि करते हैं. डिवाइस फ़ैक्ट्री से बाहर निकलने के बाद, उस कुंजी को बदला नहीं जा सकता.
मैन्युफ़ैक्चरर उस कुंजी का इस्तेमाल, पहले लेवल के बूटलोडर पर मौजूद सिग्नेचर की पुष्टि करने के लिए करते हैं. इसके बाद, बूटलोडर के अगले लेवल, ऐप्लिकेशन बूटलोडर, और आखिर में कर्नेल पर मौजूद सिग्नेचर की पुष्टि की जाती है. पुष्टि किए गए बूट का फ़ायदा पाने के लिए, हर मैन्युफ़ैक्चरर के पास कर्नेल की पूरी सुरक्षा की पुष्टि करने का तरीका होना चाहिए. मान लें कि कर्नेल की पुष्टि हो चुकी है, तो कर्नेल किसी ब्लॉक डिवाइस को देख सकता है और माउंट होने के बाद उसकी पुष्टि कर सकता है.
ब्लॉक किए गए डिवाइस की पुष्टि करने का एक तरीका यह है कि सीधे उसके कॉन्टेंट को हैश किया जाए और उनकी तुलना सेव की गई वैल्यू से की जाए. हालांकि, पूरे ब्लॉक डिवाइस की पुष्टि करने में काफ़ी समय लग सकता है और डिवाइस की ज़्यादा बैटरी खर्च हो सकती है. डिवाइसों को बूट होने में काफ़ी समय लगेगा और इस्तेमाल करने से पहले उनकी बैटरी काफ़ी कम हो जाएगी.
इसके बजाय, dm-verity हर ब्लॉक की अलग-अलग पुष्टि करता है और ऐसा सिर्फ़ तब करता है, जब हर ब्लॉक को ऐक्सेस किया जाता है. मेमोरी में पढ़ने पर, ब्लॉक को एक साथ हैश किया जाता है. इसके बाद, हैश की पुष्टि ट्री में की जाती है. ब्लॉक को पढ़ना बहुत महंगा काम है. इसलिए, ब्लॉक-लेवल की पुष्टि करने में लगने वाला समय, तुलनात्मक रूप से कम होता है.
अगर पुष्टि नहीं हो पाती है, तो डिवाइस एक I/O गड़बड़ी जनरेट करता है. इससे पता चलता है कि ब्लॉक को पढ़ा नहीं जा सकता. ऐसा लगता है कि फ़ाइल सिस्टम में गड़बड़ी है, जैसा कि उम्मीद थी.
ऐप्लिकेशन, नतीजों के डेटा के बिना भी आगे बढ़ सकते हैं. जैसे, जब उन नतीजों की ज़रूरत ऐप्लिकेशन के मुख्य फ़ंक्शन के लिए न हो. हालांकि, अगर ऐप्लिकेशन के काम करने के लिए डेटा ज़रूरी है, तो डेटा न मिलने पर वह काम नहीं करेगा.
फ़ॉरवर्ड गड़बड़ी सुधार
Android 7.0 और इसके बाद के वर्शन में, फ़ॉरवर्ड गड़बड़ी सुधार (एफ़ईसी) की सुविधा के साथ dm-verity को बेहतर बनाया गया है. AOSP को लागू करने की प्रोसेस, आम तौर पर रीड-सोलोमन गड़बड़ी ठीक करने वाले कोड से शुरू होती है. साथ ही, इंटरलेविंग नाम की एक तकनीक का इस्तेमाल करती है. इससे, स्टोरेज में जगह कम लगती है और खराब हुए उन ब्लॉक की संख्या बढ़ती है जिन्हें वापस लाया जा सकता है. एफ़ईसी के बारे में ज़्यादा जानकारी के लिए, गड़बड़ी ठीक करने की सुविधा के साथ, 'सही तरीके से बूट हुआ' सुविधा को सख्ती से लागू करना लेख पढ़ें.लागू करना
खास जानकारी
- ext4 सिस्टम इमेज जनरेट करें.
- उस इमेज के लिए हैश ट्री जनरेट करें.
- उस हैश ट्री के लिए dm-verity टेबल बनाएं.
- टेबल का हस्ताक्षर बनाने के लिए, dm-verity टेबल पर हस्ताक्षर करें.
- टेबल के हस्ताक्षर और dm-verity टेबल को, verity मेटाडेटा में बंडल करें.
- सिस्टम इमेज, पुष्टि करने के लिए मेटाडेटा, और हैश ट्री को जोड़ें.
हैश ट्री और dm-verity टेबल के बारे में ज़्यादा जानकारी के लिए, The Chromium Projects - Verified Boot देखें.
हैश ट्री जनरेट करना
शुरुआत में बताया गया था कि हैश ट्री, dm-verity के लिए ज़रूरी है. cryptsetup टूल आपके लिए हैश ट्री जनरेट करता है. इसके अलावा, यहां एक ऐसा विकल्प दिया गया है जो काम करता है:
<your block device name> <your block device name> <block size> <block size> <image size in blocks> <image size in blocks + 8> <root hash> <salt>
हैश बनाने के लिए, सिस्टम इमेज को लेयर 0 पर 4K ब्लॉक में बांटा जाता है. साथ ही, हर ब्लॉक को SHA256 हैश असाइन किया जाता है. लेयर 1, सिर्फ़ उन SHA256 हैश को 4K ब्लॉक में जोड़कर बनाई जाती है. इससे इमेज का साइज़ बहुत छोटा हो जाता है. लेयर 2, लेयर 1 के SHA256 हैश के साथ एक जैसी बनाई जाती है.
ऐसा तब तक किया जाता है, जब तक पिछली लेयर के SHA256 हैश एक ही ब्लॉक में फ़िट नहीं हो जाते. उस ब्लॉक का SHA256 हैश मिलने पर, आपके पास ट्री का रूट हैश होता है.
पुष्टि किए गए पार्टिशन के साइज़ के हिसाब से, हैश ट्री का साइज़ (और उससे जुड़े डिस्क स्पेस का इस्तेमाल) अलग-अलग होता है. आम तौर पर, हैश ट्री का साइज़ छोटा होता है. यह अक्सर 30 एमबी से कम होता है.
अगर किसी लेयर में कोई ब्लॉक है, जो पिछली लेयर के हैश से पूरी तरह से अपने-आप नहीं भरता है, तो आपको उम्मीद के मुताबिक 4K पाने के लिए, उसे शून्य से पैड करना चाहिए. इससे आपको यह पता चलता है कि हैश ट्री को हटाया नहीं गया है और इसके बजाय, उसे खाली डेटा के साथ पूरा किया गया है.
हैश ट्री जनरेट करने के लिए, लेयर 2 के हैश को लेयर 1 के हैश से जोड़ें. इसके बाद, लेयर 3 के हैश को लेयर 2 के हैश से जोड़ें. इस पूरे डेटा को डिस्क पर लिखें. ध्यान दें कि यह रूट हैश की लेयर 0 का रेफ़रंस नहीं देता.
रीकैप करने के लिए, हैश ट्री बनाने का सामान्य एल्गोरिदम यहां दिया गया है:
- कोई भी रैन्डम साल्ट (हेक्साडेसिमल एन्कोडिंग) चुनें.
- अपनी सिस्टम इमेज को 4K ब्लॉक में अनस्पेस करें.
- हर ब्लॉक के लिए, उसका (सल्ट किया गया) SHA256 हैश पाएं.
- लेवल बनाने के लिए, इन हैश को जोड़ें
- लेवल को 0 से पैड करके, 4K ब्लॉक की सीमा तक ले जाएं.
- लेवल को अपने हैश ट्री से जोड़ें.
- पिछले लेवल को अगले लेवल के सोर्स के तौर पर इस्तेमाल करके, दूसरे से लेकर छठे चरण तक दोहराएं. ऐसा तब तक करें, जब तक आपके पास सिर्फ़ एक हैश न हो.
इसकी वजह से एक हैश बनता है, जो आपका रूट हैश होता है. dm-verity मैपिंग टेबल बनाने के दौरान, इस और आपके salt का इस्तेमाल किया जाता है.
dm-verity मैपिंग टेबल बनाना
dm-verity मैपिंग टेबल बनाएं. यह टेबल, कर्नेल के लिए ब्लॉक डिवाइस (या टारगेट) और हैश ट्री की जगह की पहचान करती है. यह वैल्यू एक ही होती है. इस मैपिंग का इस्तेमाल, fstab
जनरेट करने और बूट करने के लिए किया जाता है. टेबल से ब्लॉक के साइज़ और hash_start की जानकारी भी मिलती है. hash_start, हैश ट्री की शुरुआती जगह होती है. खास तौर पर, इमेज की शुरुआत से उसका ब्लॉक नंबर.
पुष्टि करने के लिए टारगेट मैपिंग टेबल के फ़ील्ड के बारे में ज़्यादा जानकारी के लिए, cryptsetup देखें.
dm-verity टेबल पर हस्ताक्षर करना
टेबल का हस्ताक्षर बनाने के लिए, dm-verity टेबल पर हस्ताक्षर करें. किसी partition की पुष्टि करते समय, सबसे पहले टेबल के हस्ताक्षर की पुष्टि की जाती है. यह कार्रवाई, आपकी बूट इमेज में किसी तय जगह पर मौजूद कुंजी के आधार पर की जाती है. आम तौर पर, डिवाइसों पर तय जगह पर अपने-आप शामिल होने के लिए, मैन्युफ़ैक्चरर के बिल्ड सिस्टम में कुंजियां शामिल की जाती हैं.
इस हस्ताक्षर और पासकोड के कॉम्बिनेशन की मदद से, पार्टीशन की पुष्टि करने के लिए:
/verity_key
पर,/boot
partition में libmincrypt के साथ काम करने वाले फ़ॉर्मैट में RSA-2048 कुंजी जोड़ें. हैश ट्री की पुष्टि करने के लिए इस्तेमाल की गई कुंजी की जगह की पहचान करना.- काम की एंट्री के लिए fstab में,
fs_mgr
फ़्लैग मेंverify
जोड़ें.
टेबल के हस्ताक्षर को मेटाडेटा में बंडल करना
टेबल हस्ताक्षर और dm-verity टेबल को verity मेटाडेटा में बंडल करें. मेटाडेटा के पूरे ब्लॉक का वर्शन बनाया जाता है, ताकि उसे बढ़ाया जा सके. जैसे, दूसरा हस्ताक्षर जोड़ना या क्रम में बदलाव करना.
टेबल मेटाडेटा के हर सेट के साथ एक मैजिक नंबर जुड़ा होता है, ताकि टेबल की पहचान की जा सके. लंबाई को ext4 सिस्टम इमेज हेडर में शामिल किया जाता है. इससे, डेटा के कॉन्टेंट के बारे में जानने के बिना, मेटाडेटा को खोजने का एक तरीका मिलता है.
इससे यह पक्का होता है कि आपने किसी ऐसे पार्टीशन की पुष्टि नहीं की है जिसकी पुष्टि नहीं हुई है. अगर ऐसा है, तो इस मैजिक नंबर के न होने पर, पुष्टि की प्रक्रिया रुक जाती है. यह नंबर 0xb001b001
से मिलता-जुलता है.
हेक्स में बाइट वैल्यू ये हैं:
- पहला बाइट = b0
- दूसरा बाइट = 01
- तीसरा बाइट = b0
- चौथा बाइट = 01
इस डायग्राम में, पुष्टि करने वाले मेटाडेटा के बारे में बताया गया है:
<magic number>|<version>|<signature>|<table length>|<table>|<padding> \-------------------------------------------------------------------/ \----------------------------------------------------------/ | | | | 32K block content
इस टेबल में, उन मेटाडेटा फ़ील्ड के बारे में बताया गया है.
टेबल 1. मेटाडेटा फ़ील्ड की पुष्टि करना
फ़ील्ड | मकसद | साइज़ | वैल्यू |
---|---|---|---|
मैजिक नंबर | fs_mgr इसका इस्तेमाल, सही होने की जांच के तौर पर करता है | चार बाइट | 0xb001b001 |
वर्शन | मेटाडेटा ब्लॉक का वर्शन तय करने के लिए इस्तेमाल किया जाता है | चार बाइट | फ़िलहाल 0 |
हस्ताक्षर | PKCS1.5 पैड किए गए फ़ॉर्मैट में टेबल का हस्ताक्षर | 256 बाइट | |
टेबल की लंबाई | dm-verity टेबल की लंबाई, बाइट में | चार बाइट | |
टेबल | पहले बताई गई dm-verity टेबल | टेबल की लंबाई के बाइट | |
पैडिंग | इस स्ट्रक्चर को 0 से पैड करके 32 हज़ार तक लंबा किया गया है | 0 |
dm-verity को ऑप्टिमाइज़ करना
dm-verity से सबसे अच्छी परफ़ॉर्मेंस पाने के लिए, आपको:
- कर्नेल में, ARMv7 के लिए NEON SHA-2 और ARMv8 के लिए SHA-2 एक्सटेंशन चालू करें.
- अपने डिवाइस के लिए सबसे अच्छा कॉन्फ़िगरेशन ढूंढने के लिए, read-ahead और prefetch_cluster की अलग-अलग सेटिंग आज़माएं.