Android签名文件

作者: gczxbb | 来源:发表于2019-04-14 00:04 被阅读35次

在Android应用程序打包成Apk的过程中,为防止生成的Apk被篡改,需要进行签名,生成一个签名包。在Apk的META-INF目录下,有三个文件CERT.SF,MANIFEST.MF和CERT.RSA,它们的作用是对Apk内的所有文件进行编解码验证,确保用户安装的是官方发布的Apk包。

Apk的签名文件

一、MANIFEST.MF文件

Name: AndroidManifest.xml
SHA-256-Digest: vXdzhLVz8GptiwYOXfa8L3DNtsl/TIpygI+PZL0n/X0=

Name: META-INF/android.arch.core_runtime.version
SHA-256-Digest: zFL2eISLgUNzdXtGA4O/YZYOSUPCA3Na3eCjULPlCYk=

Name: res/anim/abc_fade_out.xml
SHA-256-Digest: dyKjxQwRIZ2twlcCaD3N+XtCHcKd806BO6cxWo36qh0=
...

文件内容是摘要,Apk中的所有文件,非文件夹,逐个进行sha-256,再base64计算。其中Name字段是Apk中的文件路径,SHA-256-Digest字段是每个文件的sha-256值再进行base64的结果。

通过命令将每个文件生成它的sha-256值,不同的平台都有相关命令。在Mac电脑上命令如下。

openssl dgst -sha256 文件路径

解压Apk,获取到AndroidManifest.xml文件,执行上面命令。

AndroidManifest文件的sha-256值

bd777384b573f06a6d8b060e5df6bc2f70cdb6c97f4c8a72808f8f64bd27fd7d
这串字符就是获取到的该文件sha-256值,它是16进制的,先转换成字节数组,再转换base64值,下面是字节数组+base64转换方法。

public static String toByteArray(String str) {
    //String str = "bd777384b573f06a6d8b060e5df6bc2f70cdb6c97f4c8a72808f8f64bd27fd7d";
    byte[] src = new byte[str.length() / 2];
    int k = 0;
    for (int i = 0; i < src.length; i++) {
        byte high = (byte) (Character.digit(str.charAt(k), 16) & 0xff);
        byte low = (byte) (Character.digit(str.charAt(k + 1), 16) & 0xff);
        src[i] = (byte) (high << 4 | low);
        k += 2;
    }
    String des = "";
    try {
        des = android.util.Base64.encodeToString(src, android.util.Base64.DEFAULT);
    } catch (Exception e) {
    }
    return des;
}

经过base64转换,最终的字符串。

屏幕快照 .png

经过对比MANIFEST.MF文件,发现和Name字段为AndroidManifest.xml的SHA-256-Digest值一致。
注意,不要直接将sha-256值拿到网上去进行base64编码,会当成字符串进行编码,而不是16进制,编码值是错误的,将16进制转换字节数组进行编码,才能得到正确的值。

综上,打包时,Apk中除了文件夹外的所有文件都生成sha-256值,base64编码,保存在MANIFEST.MF文件中。

经过测试,同一套代码,当改变build工具buildToolsVersion版本,在27以下版本和28版本时,AndroidManifest.xml摘要在MANIFEST.MF文件中的值是不同的,下面是buildToolsVersion28版本的摘要值。

Name: AndroidManifest.xml
SHA-256-Digest: oW/hNRRbsn6AF3U690UPEe7Z9RD4uiFtPl3QbQSeMDM=

但是,一些静态图片文件的摘要值相同,经查看,是因为使用28版本build工具会在AndroidManifest文件多插入几行内容,导致文件改变了,sha-256值自然会改变。

buildToolsVersion是28.0.3版本 buildToolsVersion是27.0.2版本

二、CERT.SF文件

Signature-Version: 1.0
Created-By: 1.0 (Android)
SHA-256-Digest-Manifest: KgN+jZmO5ZWFqV08U+s3kRBaboJNXt1VdLLF/HMKcBM=
X-Android-APK-Signed: 2

Name: AndroidManifest.xml
SHA-256-Digest: 3Ydc2Q6uqYweLyGPrhcsI1fWoOmiBsN9O7Udq3hQP6U=

Name: META-INF/android.arch.core_runtime.version
SHA-256-Digest: I65bgli5vdqHKel7MD74YlSuuyCR/5NDrXr2kf5FigA=

该文件也是摘要签名。对比MANIFEST.MF文件,多了SHA-256-Digest-Manifest这项,该项摘要是对MANIFEST.MF文件提取sha-256值,base64编码,和上面的流程一样。
其他项和MANIFEST.MF文件有相同的Name字段,它是对MANIFEST.MF文件里的每一项再次进行一次sha-256和base64编码。
注意,这里的每一项,是指将Name和SHA-256-Digest的字段和值整体提取出来,保存在文件中,对该文件进行sha-256和base64编码。

屏幕快照 .png

新建一个文件,名字随便取,将整个AndroidManifest.xml摘要项复制出来,蓝色区域,贴到新文件中,相同命令,获取新文件sha-256值,再次base64。
注意,最好直接复制,因为还有\r\n换行符。
经过base64转换,最终的字符串。

AndroidManifest摘要项提取摘要

经过对比CERT.SF文件,发现和Name字段为AndroidManifest.xml的SHA-256-Digest值一致。

综上,将MANIFEST.MF文件和文件中的每一项摘要再进行一次摘要提取+base64编码,保存在CERT.SF文件。
每项包括Name和SHA-256-Digest的字段和值,MANIFEST.MF文件的摘要项是SHA-256-Digest-Manifest。


三、CERT.RSA文件

经过以上摘要和base64编码,如果我们改了官方发布包Apk的某一个文件,二次打包Apk,没修改MANIFEST.MF文件,就会导致安装失败。
当然,也可以改MANIFEST.MF文件中的对应项,重新提取摘要。同样,也需要改CERT.SF文件,这里也会验证,该对应文件项和MANIFEST.MF项。
最后,有一个CERT.RSA验证。CERT.RSA是对CERT.SF文件进行签名的文件,需要openssl命令查看,内容包括公钥,加密算法,用开发者私钥对CERT.SF文件加密后的值。

当修改了MANIFEST.MF文件和CERT.SF文件,如果没有私钥,就无法生成正确的CERT.RSA文件。
如果不修改CERT.RSA文件,在安装时,公钥解密的CERT.SF文件内容肯定与你改过的不符,安装失败。

查看打包Apk使用的签名证书,在Mac电脑,进入工程主目录,keystore证书在该目录下保存,keytool命令。

keytool -list -v -keystore keystore -storepass 123456

第二个keystore是证书名称,123456是密码,获得证书内容。

证书内容

查看CERT.RSA证书内容,和打包签名的证书指纹内容相同,是签名公钥。

证书内容

任重而道远

相关文章

网友评论

    本文标题:Android签名文件

    本文链接:https://www.haomeiwen.com/subject/mkyrwqtx.html