APK सिग्नेचर स्कीम v2, पूरी फ़ाइल के लिए सिग्नेचर स्कीम है. इससे पुष्टि की स्पीड बढ़ती है और APK के सुरक्षित हिस्सों में हुए किसी भी बदलाव का पता चलता है. इससे पूरी सुरक्षा की गारंटी को बेहतर बनाया जाता है.
APK सिग्नेचर स्कीम v2 का इस्तेमाल करके साइन करने पर, ZIP सेंट्रल डायरेक्ट्री सेक्शन से ठीक पहले, APK फ़ाइल में APK साइनिंग ब्लॉक डाला जाता है. APK साइनिंग ब्लॉक में, v2 सिग्नेचर और साइन करने वाले की पहचान की जानकारी को APK सिग्नेचर स्कीम v2 ब्लॉक में सेव किया जाता है.
पहली इमेज. साइन करने से पहले और बाद में APK
APK सिग्नेचर स्कीम v2 को Android 7.0 (Nougat) में लॉन्च किया गया था. Android 6.0 (Marshmallow) और उससे पहले के वर्शन वाले डिवाइसों पर APK इंस्टॉल करने के लिए, v2 स्कीम से साइन करने से पहले, APK को JAR साइनिंग का इस्तेमाल करके साइन किया जाना चाहिए.
APK साइनिंग ब्लॉक
APK के v1 फ़ॉर्मैट के साथ बैकवर्ड-कंपैटिबिलिटी बनाए रखने के लिए, v2 और नए APK के सिग्नेचर को APK साइनिंग ब्लॉक में सेव किया जाता है. यह एक नया कंटेनर है, जिसे APK सिग्नेचर स्कीम v2 के साथ काम करने के लिए लॉन्च किया गया है. APK फ़ाइल में, APK साइनिंग ब्लॉक, ZIP सेंट्रल डायरेक्ट्री के ठीक पहले होता है. यह फ़ाइल के आखिर में होता है.
ब्लॉक में आईडी-वैल्यू पेयर इस तरह से होते हैं कि APK में ब्लॉक को आसानी से ढूंढा जा सकता है. APK के v2 सिग्नेचर को आईडी-वैल्यू के जोड़े के तौर पर सेव किया जाता है. इस जोड़े का आईडी 0x7109871a होता है.
फ़ॉर्मैट करें
APK हस्ताक्षर ब्लॉक का फ़ॉर्मैट यहां दिया गया है (सभी संख्या वाले फ़ील्ड, लिटल-एंडियन हैं):
size of block
बाइट में (इस फ़ील्ड को छोड़कर) (uint64)- uint64-length-prefixed आईडी-वैल्यू पेयर का क्रम:
ID
(uint32)value
(वैरिएबल-लेंथ: पेयर की लंबाई - 4 बाइट)
size of block
बाइट में—यह पहले फ़ील्ड (uint64) जैसा ही हैmagic
“APK Sig Block 42” (16 बाइट)
APK को पार्स करने के लिए, सबसे पहले ZIP सेंट्रल डायरेक्ट्री की शुरुआत का पता लगाया जाता है. इसके लिए, फ़ाइल के आखिर में मौजूद सेंट्रल डायरेक्ट्री के आखिर में मौजूद रिकॉर्ड को ढूंढा जाता है. इसके बाद, रिकॉर्ड से सेंट्रल डायरेक्ट्री के शुरू होने का ऑफ़सेट पढ़ा जाता है. magic
वैल्यू से यह पता चलता है कि सेंट्रल डायरेक्ट्री से पहले, APK साइनिंग ब्लॉक है या नहीं. इसके बाद, size of
block
वैल्यू फ़ाइल में ब्लॉक की शुरुआत पर ले जाती है.
ब्लॉक का विश्लेषण करते समय, ऐसे आईडी-वैल्यू पेयर को अनदेखा किया जाना चाहिए जिनके आईडी की पहचान नहीं की जा सकी है.
APK सिग्नेचर स्कीम v2 ब्लॉक
APK पर एक या उससे ज़्यादा लोगों/पहचान ने हस्ताक्षर किए होते हैं. हर हस्ताक्षर को साइनिंग की से दिखाया जाता है. यह जानकारी, APK सिग्नेचर स्कीम v2 ब्लॉक के तौर पर सेव की जाती है. हस्ताक्षर करने वाले हर व्यक्ति के लिए, यह जानकारी सेव की जाती है:
- (हस्ताक्षर एल्गोरिदम, डाइजेस्ट, हस्ताक्षर) टपल. डाइजेस्ट को सेव किया जाता है, ताकि APK के कॉन्टेंट की पूरी सुरक्षा की जांच से हस्ताक्षर की पुष्टि को अलग किया जा सके.
- हस्ताक्षर करने वाले व्यक्ति की पहचान दिखाने वाली X.509 सर्टिफ़िकेट चेन.
- की-वैल्यू पेयर के तौर पर अन्य एट्रिब्यूट.
साइन करने वाले हर व्यक्ति के लिए, APK की पुष्टि की जाती है. इसके लिए, दी गई सूची में मौजूद ऐसे सिग्नेचर का इस्तेमाल किया जाता है जो काम करता हो. ऐसे हस्ताक्षरों को अनदेखा कर दिया जाता है जिनमें हस्ताक्षर के लिए इस्तेमाल किए गए एल्गोरिदम की जानकारी नहीं होती. एक से ज़्यादा हस्ताक्षर इस्तेमाल किए जा सकते हैं. ऐसे में, यह तय करना कि किस हस्ताक्षर का इस्तेमाल करना है, यह हर उपयोगकर्ता के लिए अलग-अलग होता है. इससे आने वाले समय में, हस्ताक्षर करने के बेहतर तरीकों को, पुराने सिस्टम के साथ काम करने वाले तरीके से लागू किया जा सकेगा. हमारा सुझाव है कि सबसे मज़बूत सिग्नेचर की पुष्टि करें.
फ़ॉर्मैट करें
APK सिग्नेचर स्कीम v2 ब्लॉक, APK साइनिंग ब्लॉक में आईडी
0x7109871a
के नीचे सेव होता है.
APK सिग्नेचर स्कीम v2 ब्लॉक का फ़ॉर्मैट इस तरह का है (सभी संख्या वाली वैल्यू, लिटल-इंडियन फ़ॉर्मैट में होती हैं. लंबाई के प्रीफ़िक्स वाले सभी फ़ील्ड, लंबाई के लिए uint32 का इस्तेमाल करते हैं):
- लंबाई के प्रीफ़िक्स वाले
signer
का लंबाई के प्रीफ़िक्स वाला क्रम:- लंबाई के प्रीफ़िक्स वाला
signed data
:- लंबाई के प्रीफ़िक्स वाले
digests
का लंबाई के प्रीफ़िक्स वाला क्रम:signature algorithm ID
(uint32)- (length-prefixed)
digest
—पूरी सुरक्षा के साथ सुरक्षित किया गया कॉन्टेंट देखें
- X.509
certificates
का लंबाई-प्रीफ़िक्स वाला क्रम:- लंबाई के प्रीफ़िक्स वाला X.509
certificate
(ASN.1 DER फ़ॉर्म)
- लंबाई के प्रीफ़िक्स वाला X.509
- लंबाई के प्रीफ़िक्स वाले
additional attributes
का लंबाई के प्रीफ़िक्स वाला क्रम:ID
(uint32)value
(वैरिएबल-लेंथ: अन्य एट्रिब्यूट की लंबाई - 4 बाइट)
- लंबाई के प्रीफ़िक्स वाले
- लंबाई के प्रीफ़िक्स वाले
signatures
का लंबाई के प्रीफ़िक्स वाला क्रम:signature algorithm ID
(uint32)- लंबाई के प्रीफ़िक्स
signature
,signed data
से ज़्यादा
- लंबाई के प्रीफ़िक्स वाला
public key
(SubjectPublicKeyInfo, ASN.1 DER फ़ॉर्म)
- लंबाई के प्रीफ़िक्स वाला
हस्ताक्षर एल्गोरिदम आईडी
- 0x0101—SHA2-256 डाइजेस्ट, SHA2-256 MGF1, 32 बाइट का साल्ट, ट्रेलर: 0xbc के साथ RSASSA-PSS
- 0x0102—SHA2-512 डाइजेस्ट, SHA2-512 MGF1, 64 बाइट का साल्ट, और ट्रेलर: 0xbc के साथ RSASSA-PSS
- 0x0103—SHA2-256 डाइजेस्ट के साथ RSASSA-PKCS1-v1_5. यह उन बिल्ड सिस्टम के लिए है जिनमें डिटरमिनिस्टिक हस्ताक्षर ज़रूरी होते हैं.
- 0x0104—SHA2-512 डाइजेस्ट के साथ RSASSA-PKCS1-v1_5. यह उन बिल्ड सिस्टम के लिए है जिनमें डिटरमिनिस्टिक हस्ताक्षर ज़रूरी होते हैं.
- 0x0201—SHA2-256 डाइजेस्ट के साथ ईसीडीए
- 0x0202—SHA2-512 डाइजेस्ट के साथ ECDSA
- 0x0301—SHA2-256 डाइजेस्ट के साथ डीएसए
ऊपर बताए गए सभी हस्ताक्षर एल्गोरिदम, Android प्लैटफ़ॉर्म पर काम करते हैं. हस्ताक्षर करने वाले टूल, एल्गोरिदम के सबसेट के साथ काम कर सकते हैं.
इस्तेमाल किए जा सकने वाले पासकोड के साइज़ और ईसी कर्व:
- आरएसए: 1024, 2048, 4096, 8192, 16384
- ईसी: एनआईएसटी P-256, P-384, P-521
- डीएसए: 1024, 2048, 3072
अपने-आप पूरी सुरक्षा देने की सुविधा वाले कॉन्टेंट
APK के कॉन्टेंट को सुरक्षित रखने के लिए, इसमें चार सेक्शन होते हैं:
- ZIP एंट्री का कॉन्टेंट (ऑफ़सेट 0 से लेकर APK साइनिंग ब्लॉक की शुरुआत तक)
- APK साइनिंग ब्लॉक
- ZIP सेंट्रल डायरेक्ट्री
- ZIP End of Central Directory
दूसरी इमेज. साइन करने के बाद APK के सेक्शन
APK सिग्नेचर स्कीम v2, सेक्शन 1, 3, 4, और सेक्शन 2 में मौजूद APK सिग्नेचर स्कीम v2 ब्लॉक के signed data
ब्लॉक की अखंडता को सुरक्षित रखता है.
सेक्शन 1, 3, और 4 की पूरी सुरक्षा के लिए, उनके कॉन्टेंट के एक या एक से ज़्यादा डाइजेस्ट को signed data
ब्लॉक में सेव किया जाता है. इन ब्लॉक को एक या एक से ज़्यादा हस्ताक्षरों से सुरक्षित किया जाता है.
सेक्शन 1, 3, और 4 के डाइजेस्ट का हिसाब इस तरह लगाया जाता है, जैसे कि दो लेवल वाले Merkle tree में किया जाता है.
हर सेक्शन को एक एमबी (220 बाइट) के लगातार चंक में बांटा जाता है. हर सेक्शन का आखिरी हिस्सा छोटा हो सकता है. हर चंक का डाइजेस्ट, बाइट 0xa5
, बाइट में चंक की लंबाई (लिटल-इंडियन uint32), और चंक के कॉन्टेंट को जोड़कर कैलकुलेट किया जाता है. टॉप-लेवल डाइजेस्ट का हिसाब, बाइट 0x5a
, चंक की संख्या (लिटल-इंडियन uint32), और चंक के डाइजेस्ट को जोड़कर लगाया जाता है. यह हिसाब, APK में चंक के दिखने के क्रम में लगाया जाता है. डाइजेस्ट का हिसाब, एक साथ कई हिस्सों में लगाया जाता है, ताकि कैलकुलेशन को तेज़ किया जा सके.
तीसरी इमेज. APK डाइजेस्ट
सेक्शन 4 (ZIP सेंट्रल डायरेक्ट्री का आखिरी हिस्सा) को सुरक्षित करना मुश्किल है, क्योंकि इसमें सेंट्रल डायरेक्ट्री का ऑफ़सेट शामिल होता है. जब APK साइनिंग ब्लॉक का साइज़ बदलता है, तो ऑफ़सेट बदल जाता है. उदाहरण के लिए, जब कोई नया हस्ताक्षर जोड़ा जाता है. इसलिए, ZIP के सेंट्रल डायरेक्ट्री के आखिर में मौजूद डाइजेस्ट का हिसाब लगाते समय, ZIP सेंट्रल डायरेक्ट्री के ऑफ़सेट वाले फ़ील्ड को APK साइनिंग ब्लॉक के ऑफ़सेट वाले फ़ील्ड के तौर पर माना जाना चाहिए.
रोलबैक से जुड़ी सुरक्षा
हमलावर, v2 से हस्ताक्षर किए गए APK की पुष्टि, v1 से हस्ताक्षर किए गए APK के तौर पर करने की कोशिश कर सकता है. ऐसा उन Android प्लैटफ़ॉर्म पर किया जा सकता है जिन पर v2 से हस्ताक्षर किए गए APK की पुष्टि की जा सकती है. इस हमले को कम करने के लिए, v2 और v1, दोनों वर्शन से साइन किए गए APK में, META-INF/*.SF फ़ाइलों के मुख्य सेक्शन में X-Android-APK-Signed एट्रिब्यूट होना चाहिए. इस एट्रिब्यूट की वैल्यू, APK सिग्नेचर स्कीम आईडी का एक सेट होता है. इसे कॉमा लगाकर अलग किया जाता है. इस स्कीम का आईडी 2 होता है. v1 सिग्नेचर की पुष्टि करते समय, APK की पुष्टि करने वाले टूल को उन APK को अस्वीकार करना होगा जिनमें APK सिग्नेचर स्कीम के लिए कोई हस्ताक्षर नहीं है.यह स्कीम, पुष्टि करने वाले टूल के लिए इस सेट में से सबसे सही होती है. जैसे, v2 स्कीम. यह सुरक्षा इस बात पर निर्भर करती है कि कॉन्टेंट META-INF/*.SF फ़ाइलें, वर्शन 1 के हस्ताक्षरों से सुरक्षित हैं. JAR से हस्ताक्षर किए गए APK की पुष्टि सेक्शन देखें.
हमलावर, APK हस्ताक्षर स्कीम v2 ब्लॉक से ज़्यादा सुरक्षित हस्ताक्षर हटाने की कोशिश कर सकता है. इस हमले को कम करने के लिए, हस्ताक्षर करने वाले एल्गोरिदम के आईडी की सूची को signed data
ब्लॉक में सेव किया जाता है. इस सूची में मौजूद हर आईडी को हर हस्ताक्षर से सुरक्षित किया जाता है.
पुष्टि करें
Android 7.0 और इसके बाद के वर्शन में, APKs की पुष्टि APK सिग्नेचर स्कीम v2+ या JAR साइनिंग (v1 स्कीम) के हिसाब से की जा सकती है. पुराने प्लैटफ़ॉर्म, v2 साइन किए गए APK को अनदेखा करते हैं और सिर्फ़ v1 साइन किए गए APK की पुष्टि करते हैं.
चौथी इमेज. APK के हस्ताक्षर की पुष्टि करने की प्रोसेस (लाल रंग में नए चरण)
APK सिग्नेचर स्कीम v2 की पुष्टि
- APK साइनिंग ब्लॉक ढूंढें और पुष्टि करें कि:
- APK हस्ताक्षर करने वाले ब्लॉक के दो साइज़ फ़ील्ड में एक ही वैल्यू है.
- ZIP सेंट्रल डायरेक्ट्री के बाद, ZIP सेंट्रल डायरेक्ट्री का आखिरी रिकॉर्ड आता है.
- ज़िप सेंट्रल डायरेक्ट्री के आखिर में कोई और डेटा नहीं होता.
- APK साइनिंग ब्लॉक में, APK सिग्नेचर स्कीम v2 का पहला ब्लॉक ढूंढें. अगर v2 ब्लॉक मौजूद है, तो तीसरे चरण पर जाएं. अगर ऐसा नहीं है, तो v1 स्कीम का इस्तेमाल करके, APK की पुष्टि करें.
- APK सिग्नेचर स्कीम v2 ब्लॉक में मौजूद हर
signer
के लिए:signatures
में से सबसे अच्छाsignature algorithm ID
चुनें. सुरक्षा के लेवल का क्रम, लागू करने/प्लैटफ़ॉर्म के हर वर्शन पर निर्भर करता है.public key
का इस्तेमाल करके,signatures
के साथsignature
की पुष्टि करें.signed data
(signed data
को पार्स करना अब सुरक्षित है.)- पुष्टि करें कि
digests
औरsignatures
में, हस्ताक्षर एल्गोरिदम आईडी की क्रम से लगाई गई सूची एक जैसी हो. (इससे हस्ताक्षर हटाने/जोड़ने से रोका जा सकता है.) - APK के कॉन्टेंट का डाइजेस्ट कैलकुलेट करें. इसके लिए, उसी डाइजेस्ट एल्गोरिदम का इस्तेमाल करें जिसका इस्तेमाल सिग्नेचर एल्गोरिदम करता है.
- पुष्टि करें कि कैलकुलेट किया गया डाइजेस्ट,
digests
केdigest
से मेल खाता हो. - पुष्टि करें कि
certificates
के पहलेcertificate
का SubjectPublicKeyInfo,public key
से मेल खाता हो.
- अगर कम से कम एक
signer
मिला और मिले हुए हरsigner
के लिए तीसरे चरण की पुष्टि हो गई, तो पुष्टि हो जाती है.
ध्यान दें: अगर तीसरे या चौथे चरण में कोई गड़बड़ी होती है, तो APK की पुष्टि v1 स्कीम का इस्तेमाल करके नहीं की जानी चाहिए.
JAR से साइन किए गए APK की पुष्टि करना (v1 स्कीम)
हस्ताक्षर किए गए JAR फ़ॉर्मैट में APK, हस्ताक्षर किए गए स्टैंडर्ड JAR फ़ॉर्मैट होता है. इसमें META-INF/MANIFEST.MF में दी गई एंट्री ही होनी चाहिए. साथ ही, सभी एंट्री पर एक ही व्यक्ति या ग्रुप ने हस्ताक्षर किए होने चाहिए. इसकी पुष्टि इस तरह की जाती है:
- हस्ताक्षर करने वाले हर व्यक्ति को META-INF/<signer>.SF और META-INF/<signer>.(RSA|DSA|EC) JAR एंट्री से दिखाया जाता है.
- <signer>.(RSA|DSA|EC) एक ऐसा PKCS #7 CMS ContentInfo है जिसमें SignedData स्ट्रक्चर है. इस हस्ताक्षर की पुष्टि, <signer>.SF फ़ाइल से की जाती है.
- <signer>.SF फ़ाइल में, META-INF/MANIFEST.MF की पूरी फ़ाइल का डाइजेस्ट और META-INF/MANIFEST.MF के हर सेक्शन का डाइजेस्ट होता है. MANIFEST.MF की पूरी फ़ाइल के डाइजेस्ट की पुष्टि की गई हो. अगर ऐसा नहीं होता है, तो हर MANIFEST.MF के सेक्शन के डाइजेस्ट की पुष्टि की जाती है.
- META-INF/MANIFEST.MF में, पूरी सुरक्षा वाली हर JAR एंट्री के लिए, एक ऐसा सेक्शन होता है जिसका नाम एंट्री के नाम से मिलता-जुलता होता है. इसमें एंट्री के अनकंप्रेस किए गए कॉन्टेंट का डाइजेस्ट होता है. इन सभी डाइजेस्ट की पुष्टि की गई है.
- अगर APK में ऐसी JAR एंट्री शामिल हैं जो MANIFEST.MF में शामिल नहीं हैं और JAR सिग्नेचर का हिस्सा नहीं हैं, तो APK की पुष्टि नहीं हो पाती.
इसलिए, सुरक्षा की चेन इस तरह है: <signer>.(RSA|DSA|EC) -> <signer>.SF -> MANIFEST.MF -> पूरी सुरक्षा वाली हर JAR एंट्री का कॉन्टेंट.