APK सिग्नेचर स्कीम v4

Android 11 में, APK सिग्नेचर स्कीम v4 के साथ स्ट्रीमिंग के लिए सही तरीके से साइन करने की सुविधा काम करती है. v4 सिग्नेचर, Merkle हैश ट्री पर आधारित होता है. इसकी गिनती, APK के सभी बाइट पर की जाती है. यह स्कीम, fs-verity हैश ट्री के स्ट्रक्चर को पूरी तरह से फ़ॉलो करती है. उदाहरण के लिए, सॉल्ट में ज़ीरो-पैडिंग और आखिरी ब्लॉक में ज़ीरो-पैडिंग. Android 11, सिग्नेचर को एक अलग फ़ाइल, <apk name>.apk.idsig में सेव करता है. v4 सिग्नेचर के लिए, v2 या v3 सिग्नेचर की ज़रूरत होती है.

फ़ाइल फ़ॉर्मैट

सभी संख्या वाले फ़ील्ड, लिटिल एंडियन में होते हैं. सभी फ़ील्ड, sizeof() के तौर पर बाइट की उतनी ही संख्या का इस्तेमाल करते हैं. इनमें कोई भी डिफ़ॉल्ट पैडिंग या अलाइनमेंट नहीं जोड़ा जाता है.

नीचे दिए गए हेल्पर स्ट्रक्चर से, परिभाषाओं को आसान बनाया गया है:

template <class SizeT>
struct sized_bytes {
        SizeT size;
        byte bytes[size];
};

मुख्य फ़ाइल का कॉन्टेंट:

struct V4Signature {
        int32 version; // only version 2 is supported as of now
        sized_bytes<int32> hashing_info;
        sized_bytes<int32> signing_info;
        sized_bytes<int32> merkle_tree;  // optional
};

hashing_info हैश ट्री जनरेट करने के लिए इस्तेमाल किया जाने वाला पैरामीटर है. साथ ही, यह रूट हैश भी है:

struct hashing_info.bytes {
    int32 hash_algorithm;    // only 1 == SHA256 supported
    int8 log2_blocksize;     // only 12 (block size 4096) supported now
    sized_bytes<int32> salt; // used exactly as in fs-verity, 32 bytes max
    sized_bytes<int32> raw_root_hash; // salted digest of the first Merkle tree page
};

signing_info यह स्ट्रक्चर है:

struct signing_info.bytes {
    sized_bytes<int32> apk_digest; // used to match with the corresponding APK
    sized_bytes<int32> x509_certificate; // ASN.1 DER form
    sized_bytes<int32> additional_data; // a free-form binary data blob
    sized_bytes<int32> public_key; // ASN.1 DER, must match the x509_certificate
    int32 signature_algorithm_id; // see the APK v2 doc for the list
    sized_bytes<int32> signature;
};

apk_digest को APK के v3 साइनिंग ब्लॉक से लिया जाता है. अगर यह ब्लॉक मौजूद नहीं है, तो इसे v2 ब्लॉक से लिया जाता है. इसके लिए, apk_digest देखें.

signature कोड को बनाने और उसकी पुष्टि करने के लिए, इस डेटा को बाइनरी ब्लोब में क्रम से लगाना होगा. साथ ही, इसे हस्ताक्षर करने और पुष्टि करने वाले एल्गोरिदम में हस्ताक्षर किया गया डेटा के तौर पर पास करना होगा:

struct V4DataForSigning {
        int32 size;
        int64 file_size; // the size of the file that's been hashed.
        hashing_info.hash_algorithm;
        hashing_info.log2_blocksize;
        hashing_info.salt;
        hashing_info.raw_root_hash;
        signing_info.apk_digest;
        signing_info.x509_certificate;
        signing_info.additional_data;
};

merkle_tree, APK का पूरा Merkle ट्री है. इसे fs-verity दस्तावेज़ में बताए गए तरीके से कैलकुलेट किया जाता है.

प्रोड्यूसर और उपभोक्ता

डिफ़ॉल्ट पैरामीटर के साथ चलाने पर, apksigner Android SDK टूल, v4 सिग्नेचर फ़ाइल जनरेट करता है. v4 पर हस्ताक्षर करने की सुविधा को उसी तरह बंद किया जा सकता है जिस तरह हस्ताक्षर करने की अन्य स्कीमें बंद की जाती हैं. यह टूल, v4 सिग्नेचर के मान्य होने की पुष्टि भी कर सकता है.

adb कमांड चलाने पर, adb को उम्मीद होती है कि .apk.idsig फ़ाइल, APK के बगल में मौजूद हो.adb install --incremental adb डिफ़ॉल्ट रूप से, इंक्रीमेंटल इंस्टॉलेशन के लिए IDSIG फ़ाइल का इस्तेमाल करता है. अगर यह फ़ाइल मौजूद नहीं है या अमान्य है, तो यह सामान्य इंस्टॉलेशन पर वापस आ जाता है.

जब कोई इंस्टॉलेशन सेशन बनाया जाता है, तो PackageInstaller में मौजूद नया स्ट्रीमिंग इंस्टॉलेशन एपीआई, सेशन में कोई फ़ाइल जोड़ते समय, स्ट्रिप्ड v4 सिग्नेचर को अलग आर्ग्युमेंट के तौर पर स्वीकार करता है. इस समय, signing_info को IncFS में पूरे ब्लब के तौर पर पास किया जाता है. IncFS, ब्लोब से रूट हैश निकालता है.

इंस्टॉलेशन सेशन को कमिट करते समय, PackageManagerService, IncFS को ioctl कॉल करके signing_info blob को वापस पाता है. इसके बाद, वह blob को पार्स करता है और हस्ताक्षर की पुष्टि करता है.

इंक्रीमेंटल डेटा लोडर कॉम्पोनेंट, डेटा लोडर नेटिव एपीआई के ज़रिए हस्ताक्षर के Merkle ट्री वाले हिस्से को स्ट्रीम करता है. package service shell command install-incremental, जोड़े गए हर फ़ाइल के लिए पैरामीटर के तौर पर, Base64 के तौर पर एन्कोड की गई v4 सिग्नेचर फ़ाइल को स्वीकार करती है. इससे जुड़ा Merkle ट्री, निर्देश के stdin में भेजा जाना चाहिए.

apk_digest

apk_digest, क्रम में उपलब्ध पहला कॉन्टेंट डाइजेस्ट है:

  1. V3, 1 एमबी ब्लॉक, SHA2-512 (CONTENT_DIGEST_CHUNKED_SHA512)
  2. V3, 4 केबी ब्लॉक, SHA2-256 (CONTENT_DIGEST_VERITY_CHUNKED_SHA256)
  3. V3, 1 एमबी ब्लॉक, SHA2-256 (CONTENT_DIGEST_CHUNKED_SHA256)
  4. V2, SHA2-512
  5. V2, SHA2-256

APK सिग्नेचर स्कीम v3 में, length-prefixed signer की length-prefixed sequence देखें.

पुष्टि करना और जांच करना

नीचे दी गई इमेज में, APK की पुष्टि करने की प्रोसेस v4 के बारे में बताया गया है:

APK की पुष्टि करने की प्रोसेस v4

पहली इमेज. APK की पुष्टि करने की प्रोसेस v4.

सुविधा की यूनिट टेस्ट और सीटीएस का इस्तेमाल करके, लागू करने की पुष्टि करें:

  • CtsIncrementalInstallHostTestCases
  • /android/cts/hostsidetests/incrementalinstall

हस्ताक्षर के फ़ॉर्मैट की जांच करना

हस्ताक्षर के फ़ॉर्मैट की जांच करने के लिए, बिल्ड एनवायरमेंट सेट अप करें और ये मैन्युअल टेस्ट चलाएं:

$ atest PackageManagerShellCommandTest
PackageManagerShellCommandIncrementalTest

Android SDK (ADB और apksigner) की मदद से, हस्ताक्षर के फ़ॉर्मैट की जांच करना

Android SDK की मदद से, सिग्नेचर फ़ॉर्मैट की जांच करने के लिए यह तरीका अपनाएं:

  1. बिल्ड एनवायरमेंट सेट अप करें और पक्का करें कि आपने IncFS को लागू कर दिया हो.
  2. टारगेट किए गए फ़िज़िकल डिवाइस या एम्युलेटर पर बिल्ड फ़्लैश करें.
  3. कोई मौजूदा एपीके जनरेट करें या पाएं. इसके बाद, डीबग साइनिंग की बनाएं.
  4. build-tools फ़ोल्डर से, v4 सिग्नेचर फ़ॉर्मैट का इस्तेमाल करके APK पर साइन करें और उसे इंस्टॉल करें.

    साइन
    $ ./apksigner sign --ks debug.keystore game.apk

    इंस्टॉल करें
    $ ./adb install game.apk

    ये टेस्ट कहां मिल सकते हैं
    /android/cts/tests/tests/content/src/android/content/pm/cts/PackageManagerShellCommandIncrementalTest.java