background

In order to avoid the system being installed with a variety of apps, the customer required the system to have a whitelist installation function.

Train of thought

The whitelist function is used to check whether the application to be installed is on the whitelist. If not, the application cannot be installed. The filtering criteria can be determined by the package name. However, it is not safe to judge only the packet name. Here we want to add a signature verification mechanism, after all, each signature is unique.

In this process, the main difficulty is how to obtain each APK signature. Before explaining how to get the system signature in your code, let me give you a quick overview of the Android application signature mechanism.

Android App Signature

The basic purpose of signing is not to allow the contents of any file in apK to be tampered with. So make sure every file is encrypted to. Unzip any signed APK and you’ll find a meta-INF folder that contains, but is not limited to, the following three files:

CERT. RSACERT. SFMANIFEST. MFCopy the code

1. The MANIFEST. Manifest.mf. Each file in the APK package (except folders and signature files) is traversed, using SHA1 or SHA256 to generate summary information. The manifest.mf file is encoded in base64, and a segment of the manifest.mf file is captured:

Name: AndroidManifest.xml
SHA1-Digest: D2yOY7wstlBC3AbjQznUDa6/8Xw=
Copy the code

Androidmanifest.xml: androidmanifest.xml: androidmanifest.xml: androidmanifest.xml: androidmanifest.xml: androidManifest.xml: androidManifest.xml: androidManifest.xml: androidManifest.xml

http://www.metools.info/code/c92.html
Copy the code

After you get the abstract, you can encode the abstract through online Base64 encoding:

http://tomeko.net/online_tools/hex_to_base64.php?lang=en
Copy the code

You can see that the base64 encoding obtained here is the same as described in the manifest.mf file.

The base64 encoding of the rest of the files is computed in the same way. From here you know that if the files in APK are tampered with, you end up with a base64 encoding that is not described in the manifest.mf file, which can lead to an installation error. Of course, you could manually calculate the base64 encoding of the modified file and update it to the manifest.mf file, but that would fall short because there are also cert. RSA and cert.sf.

2. CERT. SF, file. Extract part of the document:

Signature - Version: 1.0 SHA1 Digest - Manifest: iaeBE2KJWElTbmMNGnjxretMvz8 = Created - By: 1.0 (Android SignApk) Name: kotlin/collections/MapWithDefault.kotlin_metadata SHA1-Digest: je8WuIzQjM5yX2bkDmjjyviMxOE= Name: kotlin/coroutines/intrinsics/CoroutinesIntrinsicsHKt.kotlin_meta data SHA1-Digest: reRpbwjfyR7tladgIdLzjpREduA= Name: res/interpolator/btn_checkbox_checked_mtrl_animation_interpolato r_0.xml SHA1-Digest: 9Lo7vzAcNsmM/qCg9/iamygexzk=Copy the code

This file is a SHA1 calculation of each entry in the manifest.mf file, followed by base64 encoding. In addition, the contents of the manifest.mf file are SHA1 computed and then encoded, and this value is written to the sha1-digest-manifest:

SHA1-Digest-Manifest: iaeBE2KJWElTbmMNGnjxretMvz8=
Copy the code

There is a layer of tamper protection for the manifest.mf file, and as long as the manifest.mf file has been modified, the resulting Base64 encoding will never match. Of course, at this point, if that’s all it takes, it can still be tampered with. The key is to look at the cert. RSA file.

3. CERT. RSA file. This file stores information such as the public key and the encryption algorithm used. Also important is the value after encrypting the contents of the cert. SF file with the private key. That is, even if you manually tamper with the manifest.mf and cert. SF files, the cert. RSA file will still not correspond and the installation will fail.

Apk installs whitelist for signature verification

The signing process is described above, and installation is the other way around.

RSA decrypts the digital signature (itself) and compares the decrypted result with the hash result of the cert. SF file. If the decrypted result is consistent, the certificate chain information is returned and the certificate chain is saved in the Certificates object. The cert. SF file has not been tampered with. If this comparison works, the next step is to verify that the manifest.MF has been tampered with. In this step, each entry is traversed, and the digital signature information of SHA1 is generated one by one for files that are not folders or signed files, and then encoded in Base64 and compared with the contents in manifest.mf. If there is a one-to-one match, the file is not tampered with. Here to check whether all APK files have been tampered with, has also been completed.

Obviously, if we want to implement signature verification on the installation whitelist, we can compare the certificate signature on the RSA file to the apK signature.

Obtain the certificate fingerprint of the APK signature

After getting the APP, decompress apk to obtain cert. RSA file and execute the following commands:

keytool -printcert -file CERT.RSA
Copy the code

The certificate fingerprint of the signature can be obtained:

Certificate fingerprints:
 MD5:  0E:BA:50:A4:5C:15:B3:5D:97:7D:04:D8:43:79:B3:58
 SHA1: 41:79:1C:9B:8F:AF:15:E1:AC:D5:AA:F5:92:10:FD:42:46:7D:82:70
 SHA256: 2D:37:0C:21:F5:DF:D5:53:D2:A7:96:31:4B:70:92:5F:B3:8A:DE:EF:90:86:4C:92:0B:BB:BB:12:88:7D:35:20
Copy the code

The certificate fingerprint of each signature is unique, so that the uniqueness of the certificate fingerprint can be used to verify the signature.

Android source code to obtain the certificate fingerprint

To obtain apK’s signature certificate fingerprint, you need to obtain its signature first. The package information is parsed by the PackageParser class during app installation, and the signature is also included. We can use this to get the certificate fingerprint of the signature. The preparePackageLI method of the PackageManagerService class will generate a PackageParser object to parse the APK package:

private PrepareResult preparePackageLI(InstallArgs args, PackageInstalledInfo res) throws PrepareFailure { ... PackageParser pp = new PackageParser(); pp.setSeparateProcesses(mSeparateProcesses); pp.setDisplayMetrics(mMetrics); pp.setCallback(mPackageParserCallback); Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parsePackage"); final PackageParser.Package pkg; try { pkg = pp.parsePackage(tmpPackageFile, parseFlags); DexMetadataHelper.validatePackageDexMetadata(pkg); } catch (PackageParserException e) { throw new PrepareFailure("Failed parse during installPackageLI", e); } finally { Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); }... try { // either use what we've been given or parse directly from the APK if (args.signingDetails ! = PackageParser.SigningDetails.UNKNOWN) { pkg.setSigningDetails(args.signingDetails); } else { PackageParser.collectCertificates(pkg, false /* skipVerify */); } } catch (PackageParserException e) { throw new PrepareFailure("Failed collect during installPackageLI", e); }... }Copy the code

PKG is a Pakage object that belongs to the PackageParser internal class. This class is used to store APK-related information such as package name, APK path, signature, etc.

Once the signature is obtained, the certificate fingerprint can be obtained as follows:

String sha1 = getFingerprint(pkg.mSigningDetails.signatures[0], "SHA1");

private String getFingerprint(Signature signature, String hashAlgorithm) {
    if (signature == null) {
        return null;
    }
    try {
        MessageDigest digest = MessageDigest.getInstance(hashAlgorithm);
        return toHexadecimalString(digest.digest(signature.toByteArray()));
    } catch(NoSuchAlgorithmException e) {
        // ignore
    }
    return null;
}
Copy the code

The MessageDigest class provides the application with the capabilities of information summarization algorithms, such as MD5 or SHA algorithms. An information digest is a secure one-way hash function that takes data of any size and outputs a fixed-length hash value. Here the digest is obtained based on the SHA algorithm, that is, the certificate fingerprint.

Signature verification

The fingerprint is compared with the SHA1 value obtained using the keytool. If yes, the signature is verified and the application is allowed to be installed. The specific implementation is relatively simple. You can save the SHA1 value obtained by keytool to the whitelist, and then read it for comparison during apK installation.

conclusion

What is the certificate fingerprint, or message digest, of each signature obtained by SHA1, MD5, or SHA256? Private key plus something else?

Wechat official account

I also wrote an article in the wechat public number, update more timely, interested in wechat search [Android system combat development], pay attention to surprise oh!