当前位置:网站首页>Apk signature principle

Apk signature principle

2022-07-01 14:52:00 Full stack programmer webmaster

Hello everyone , I meet you again , I'm your friend, Quan Jun .

There are many similar articles about signature analysis on the Internet , But there is a common problem , It's conceptual confusion , It's a mess .

In understanding APK Before signature principle , First, clarify a few concepts :

A summary of the news -Message Digest

Abstract for short , Please see the English translation , It's a summary , Not a signature , Almost all online APK Articles on signature analysis confuse these two concepts .

Link to summary http://en.wikipedia.org/wiki/Message_digest

Simply put, the message summary is on the message data , Perform a one-way Hash function , Generate a fixed length of Hash value , This Hash Value is the message digest, also known as digital fingerprint :

The message digest has the following characteristics :

1. The message itself cannot be inferred from the summary

2. If the message is modified , Then the summary will change ( actually , Because long plaintext generates short summary Hash There is bound to be a collision ), So this sentence is not accurate , We can change it to : It's hard to find a pattern , Modified the message , And its summary will not change .

This feature of message digest , It is suitable for verifying the integrity of data , For example, download a large file during network transmission BigFile, We will also download from the Internet BigFile and BigFile.md5,BigFile.md5 preservation BigFile A summary of the , We generate locally BigFile A summary of the news , and BigFile.md5 Compare , If the content is the same , It means that the download process is correct .

Be careful , Message digest can only guarantee the integrity of the message , There is no guarantee that the message cannot be tampered with .

MD5/SHA-0 SHA-1

These are summary generation algorithms , It has nothing to do with signatures . If you have to say that they have something to do with the signature , That is, signature is based on digest Technology .

digital signature – Signature

digital signature , Baidu Encyclopedia has a very clear introduction to digital signatures . Let me be wordy here again , If you don't understand, go to Baidu Encyclopedia .

Digital signature is that the sender of information encrypts the message digest with his private key to produce a string , The encryption algorithm ensures that others cannot forge this string , This digital string is also an effective proof of the authenticity of the information sent by the sender .

The digital signature is Asymmetric key encryption technology + Digital summarization technology The combination of .

Digital signature technology is to encrypt the information digest with the sender's private key , Send to the receiver with the original . The receiver can decrypt the encrypted information digest only with the sender's public key , Then the receiver uses the same Hash Function generates an information summary of the received original text , Compare with the decrypted information summary . If the same , It means that the information received is complete , Not modified during transmission ; Different means that the information has been modified , Therefore, digital signature can ensure the integrity of information . And because only the sender has the private key to encrypt the digest , So we can make sure that the message must be sent by the sender .

digital certificate – Certificate

Digital certificate is a certificate authorized Central digital signature file containing public key owner information and public key .CERT.RSA It contains a digital signature and a digital certificate .

It should be noted that Android APK Medium CERT.RSA The certificate is self signed , It is not necessary that this certificate is issued or certified by a third-party Authority , Users can generate this self signed certificate on their local machine .

APK Signature process analysis

After the concepts of abstract and signature are clear , We can analyze APK Signing process .Android Provides APK The signature tool for signapk , How to use it is as follows :

signapk [-w] publickey.x509[.pem] privatekey.pk8 input.jar output.jar

publickey.x509.pem Include certificates and certificate chains , Certificates and certificate chains contain public keys and encryption algorithms ;privatekey.pk8 It's the private key ;input.jar You need to sign jar;output.jar It is the result of signature

signapk Implementation in android/build/tools/signapk/SignApk.java in , The main function main The implementation is as follows

    public static void main(String[] args) {
        if (args.length != 4 && args.length != 5) {
            System.err.println("Usage: signapk [-w] " +
                    "publickey.x509[.pem] privatekey.pk8 " +
                    "input.jar output.jar");
            System.exit(2);
        }

        sBouncyCastleProvider = new BouncyCastleProvider();
        Security.addProvider(sBouncyCastleProvider);

        boolean signWholeFile = false;
        int argstart = 0;
        if (args[0].equals("-w")) {
            signWholeFile = true;
            argstart = 1;
        }

        JarFile inputJar = null;
        JarOutputStream outputJar = null;
        FileOutputStream outputFile = null;

        try {
            File publicKeyFile = new File(args[argstart+0]);
            X509Certificate publicKey = readPublicKey(publicKeyFile);

            // Assume the certificate is valid for at least an hour.
            long timestamp = publicKey.getNotBefore().getTime() + 3600L * 1000;

            PrivateKey privateKey = readPrivateKey(new File(args[argstart+1]));
            inputJar = new JarFile(new File(args[argstart+2]), false);  // Don't verify.

            OutputStream outputStream = null;
            if (signWholeFile) {
                outputStream = new ByteArrayOutputStream();
            } else {
                outputStream = outputFile = new FileOutputStream(args[argstart+3]);
            }
            outputJar = new JarOutputStream(outputStream);

            // For signing .apks, use the maximum compression to make
            // them as small as possible (since they live forever on
            // the system partition).  For OTA packages, use the
            // default compression level, which is much much faster
            // and produces output that is only a tiny bit larger
            // (~0.1% on full OTA packages I tested).
            if (!signWholeFile) {
                outputJar.setLevel(9);
            }

            JarEntry je;

            Manifest manifest = addDigestsToManifest(inputJar);

            // Everything else
            copyFiles(manifest, inputJar, outputJar, timestamp);

            // otacert
            if (signWholeFile) {
                addOtacert(outputJar, publicKeyFile, timestamp, manifest);
            }

            // 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);

            // CERT.RSA
            je = new JarEntry(CERT_RSA_NAME);
            je.setTime(timestamp);
            outputJar.putNextEntry(je);
            writeSignatureBlock(new CMSProcessableByteArray(signedData),
                                publicKey, privateKey, outputJar);

            outputJar.close();
            outputJar = null;
            outputStream.flush();

            if (signWholeFile) {
                outputFile = new FileOutputStream(args[argstart+3]);
                signWholeOutputFile(((ByteArrayOutputStream)outputStream).toByteArray(),
                                    outputFile, publicKey, privateKey);
            }
        } catch (Exception e) {
            e.printStackTrace();
            System.exit(1);
        } finally {
            try {
                if (inputJar != null) inputJar.close();
                if (outputFile != null) outputFile.close();
            } catch (IOException e) {
                e.printStackTrace();
                System.exit(1);
            }
        }
    }

Generate MAINFEST.MF file

Manifest manifest = addDigestsToManifest(inputJar);

Traverse inputJar Every file in , utilize SHA1 The algorithm generates an information summary of these files .

            // MANIFEST.MF
            je = new JarEntry(JarFile.MANIFEST_NAME);
            je.setTime(timestamp);
            outputJar.putNextEntry(je);
            manifest.write(outputJar);

Generate MAINFEST.MF file , This file contains input jar Summary value of all file contents in the package . Be careful , Summary values for the following three files will not be generated MANIFEST.MF CERT.SF and CERT.RSA

Generate CERT.SF

            // 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);

although writeSignatureFile It literally looks like writing a signed document , however CERT.SF The generation of has nothing to do with the private key , In fact, it shouldn't have anything to do with money , Naturally, this file does not save any signature content .

CERT.SF What is preserved in is MANIFEST.MF The summary value of , as well as MANIFEST.MF Summary value of each summary item in . Forgive me for being stupid , I don't know why I should introduce CERT.SF, In fact, I think the signature can be used MANIFEST.MF Generate .

signedData Namely CERT.SF The content of , This information summary will be used when making signatures .

Generate CERT.RSA

This file holds the signature and public key certificate . The private key must participate in the generation of signature , The information summary used for signature is CERT.SF Content .

            // CERT.RSA
            je = new JarEntry(CERT_RSA_NAME);
            je.setTime(timestamp);
            outputJar.putNextEntry(je);
            writeSignatureBlock(new CMSProcessableByteArray(signedData),
                                publicKey, privateKey, outputJar);

signedData This data will be used as a summary for signature ,writeSignatureBlock Function use privateKey Yes signedData Encrypt generate signature , Then save the signature and public key certificate to CERT.RSA in 、

    /** 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());
    }

Translate the comments of this function : For parameters data To sign , Then write the generated digital signature into the parameters out in

@data Is a summary of the generated signature

@publicKey; It is the certificate corresponding to the private key used for signing

@privateKey: It is the private key used in signing

@out: The output file , That is to say CERT.RSA

It is finally preserved in CERT.RSA Is in the CERT.SF Digital signature of , Signature use privateKey Generated , The signature algorithm will be in publicKey In the definition of . At the same time, it will put publicKey Store in CERT.RSA in , in other words CERT.RSA Contains the signature and the certificate used for signing . And the certificate is required to be self signed .

Publisher : Full stack programmer stack length , Reprint please indicate the source :https://javaforall.cn/131190.html Link to the original text :https://javaforall.cn

原网站

版权声明
本文为[Full stack programmer webmaster]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/182/202207011444340099.html