Android數位簽章解析(二)

來源:互聯網
上載者:User

標籤:

在Android數字簽名解析(一)中,介紹了android進行簽名的兩種方式,當中用金鑰組進行簽名用到了signapk.jar這個java庫。
以下我們就看看signapk簽名實現過程,signapk的原始碼在build/tools/signapk/下。


一、產生MANIFEST.MF檔案
      //對apk包中的每一個檔案(非目錄和非簽名檔案),產生SHA1的摘要資訊。再對這個資訊進行Base64編碼。      Manifest manifest = addDigestsToManifest(inputJar);

      //將上面得到的資訊。寫入MANIFEST.MF      je = new JarEntry(JarFile.MANIFEST_NAME);      je.setTime(timestamp);      outputJar.putNextEntry(je);      manifest.write(outputJar);

二、 產生CERT.SF檔案    
      je = new JarEntry(CERT_SF_NAME);      je.setTime(timestamp);      outputJar.putNextEntry(je);      ByteArrayOutputStream baos = new ByteArrayOutputStream();      writeSignatureFile(manifest, baos);      byte[] signedData = baos.toByteArray();      outputJar.write(signedData);

對 整個 MANIFEST.MF 進行 SHA1 計算。並將摘要資訊存入 CERT.SF 中 。然後對之前計算的全部摘要資訊使用SHA1再次計
算,將結果也寫入 CERT.SF 中, 關鍵代碼在 writeSignatureFile(manifest, baos)中,
   /** Write a .SF file with a digest of the specified manifest. */    private static void writeSignatureFile(Manifest manifest, OutputStream out)        throws IOException, GeneralSecurityException {        Manifest sf = new Manifest();        Attributes main = sf.getMainAttributes();        main.putValue("Signature-Version", "1.0");        main.putValue("Created-By", "1.0 (Android SignApk)");        MessageDigest md = MessageDigest.getInstance("SHA1");        PrintStream print = new PrintStream(                new DigestOutputStream(new ByteArrayOutputStream(), md),                true, "UTF-8");        // Digest of the entire manifest        manifest.write(print);        print.flush();        main.putValue("SHA1-Digest-Manifest",                      new String(Base64.encode(md.digest()), "ASCII"));        Map<String, Attributes> entries = manifest.getEntries();        for (Map.Entry<String, Attributes> entry : entries.entrySet()) {            // Digest of the manifest stanza for this entry.            print.print("Name: " + entry.getKey() + "\r\n");            for (Map.Entry<Object, Object> att : entry.getValue().entrySet()) {                print.print(att.getKey() + ": " + att.getValue() + "\r\n");            }            print.print("\r\n");            print.flush();            Attributes sfAttr = new Attributes();            sfAttr.putValue("SHA1-Digest",                            new String(Base64.encode(md.digest()), "ASCII"));            sf.getEntries().put(entry.getKey(), sfAttr);        }        CountOutputStream cout = new CountOutputStream(out);        sf.write(cout);        // A bug in the java.util.jar implementation of Android platforms        // up to version 1.6 will cause a spurious IOException to be thrown        // if the length of the signature file is a multiple of 1024 bytes.        // As a workaround, add an extra CRLF in this case.        if ((cout.size() % 1024) == 0) {            cout.write('\r');            cout.write('\n');        }    }


三、產生CERT.RSA檔案

 <span style="white-space:pre"></span>je = new JarEntry(CERT_RSA_NAME);        je.setTime(timestamp);        outputJar.putNextEntry(je);        writeSignatureBlock(new CMSProcessableByteArray(signedData),                                publicKey, privateKey, outputJar);

關鍵代碼在writeSignatureBlock(new CMSProcessableByteArray(signedData)中
/** Sign data and write the digital signature to 'out'. */    private static void writeSignatureBlock(        CMSTypedData data, X509Certificate publicKey, PrivateKey privateKey,        OutputStream out)        throws IOException,               CertificateEncodingException,               OperatorCreationException,               CMSException {        ArrayList<X509Certificate> certList = new ArrayList<X509Certificate>(1);        certList.add(publicKey);        JcaCertStore certs = new JcaCertStore(certList);        CMSSignedDataGenerator gen = new CMSSignedDataGenerator();        ContentSigner sha1Signer = new JcaContentSignerBuilder("SHA1withRSA")            .setProvider(sBouncyCastleProvider)            .build(privateKey);        gen.addSignerInfoGenerator(            new JcaSignerInfoGeneratorBuilder(                new JcaDigestCalculatorProviderBuilder()                .setProvider(sBouncyCastleProvider)                .build())            .setDirectSignature(true)            .build(sha1Signer, publicKey));        gen.addCertificates(certs);        CMSSignedData sigData = gen.generate(data, false);        ASN1InputStream asn1 = new ASN1InputStream(sigData.getEncoded());        DEROutputStream dos = new DEROutputStream(out);        dos.writeObject(asn1.readObject());    }


把之前產生的CERT.SF檔案,用私人密鑰計算出簽名, 然後將簽名以及公開金鑰資訊寫入 CERT.RSA 中儲存。



Android數位簽章解析(二)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.