Android签名原理

这篇博客主要介绍了Android APK的签名原理,包括如何生成签名文件、签名的作用、签名算法以及MANIFEST.MF文件的内容解析。Android签名确保了APK的完整性和防止被恶意篡改,同时也影响覆盖安装时的安全性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、如何对一个APK签名?

网上资料比较多,找了一个比较好的:

http://xlover.iteye.com/blog/1111560

简单来说,步骤为:

1、生成签名文件key.keystore,并指定签名文件的密码:

jarsigner -verbose -keystore key.keystore -signedjar notepad_signed.apk notepad.apk key.keystore

2、用签名文件key.keystore对APK进行签名:

 jarsigner -verbose -keystorekey.keystore -signedjar notepad_signed.apk notepad.apk key.keystore


二、签名的作用是什么?

这里需要补一下信息安全方面的知识,如下,数字签名的作用:

http://www.docin.com/p-99435359.html

因此,衍生出两个Android签名最重要的作用:

1、确认你的APK没有被人恶意篡改;(数字签名的作用)PS:脑补一下,QQ里面被人恶意篡改,然后你在不知情的情况下下载到

2、通过对比你的签名文件,保证在覆盖安装时,你的APP不会被其他人覆盖;(衍生作用) PS:你应该不希望自己的APP被其他人覆盖吧,除了你自己


4、签名是如何起作用的?

目前主流的签名算法,有RSA、DES等等,都是基于一些公认的数学理论;(比如RSA是基于大数分解)

简单来说,签名步骤如下:

1、使用私钥R,对数据D进行计算,得出结果S;

2、将公钥P,公布给其他人,其他任何使用P,能对数据D,结果S,进行验证。

3、如果P+S+D=验证通过,那么其他人认为数据D没有被篡改;


对应到Android中,就是(以下以RSA算法签名为案例):

私钥R:存储在key.keystore中;

公钥P:存储在key.keystore中(我自己总要存一份吧),对外存储在META-INF\CERT.RSA中(任何人都可以拿到);

数据D:APK中的每个文件(记录在META-INF\MANIFEST.MF中);

结果S:存储在META-INF\CERT.SF中;


反过来,已经明白APK中key.keystore文件的实际意义,以及META-INF以及各个文件的作用,详情如下:

key.keystore:存储私钥+公钥,用户可以通过密码提取出来;

CERT.RSA:对外暴露的公钥

MANIFEST.MF:记录APK每个文件的MD5

CERT.SF:保存签名结果

系统验证只需要保证(CERT.RSA、MANIFEST.MF、CERT.SF)能满足某一数学公式即可

附上RSA算法原理,有兴趣可以看一下签名过程以及验证过程:

http://blog.csdn.net/sunmenggmail/article/details/11994013


三、MANIFEST.MF  解析

上面已经说明了MANIFEST.MF 作用,现在详解其格式;

随便打开一个APK文件,MANIFEST.MF 格式都是:

Manifest-Version: 1.0
Created-By: 1.6.0_24 (Sun Microsystems Inc.)

Name:XXXXX

SHA1-Digest:XXXXXX

..........

..........

..........

很好理解,Name表示单个文件路径,SHA1-Digest表示MD5信息。MANIFEST.MF 存储所有APK文件的SHA1值


四、通常说的APK签名是什么?

签名指的是:android.content.pm.PackageInfo中Signature[] signatures对象

通常来说,为了方便数据计算,需要对其signatures[0] or 1 计算MD5值,转换成为string对象:

        try {
            PackageInfo packageInfo = getPackageManager()
                    .getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
            String signMd5 =  MD5.toMD5(packageInfo.signatures[packageInfo.signatures.length - 1].toCharsString());
            Log.d("Sign",signMd5);
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }

同理,在JAVA在读取签名:

    /**
     * 获取android包里面的所有证书MD5
     * @param apkFile 包文件
     * @return
     */
    public static String getSigMd5(File apkFile) {
        //解压APK文件,;略
        String unPackFile = unpack(apkFile);
        //针对使用RSA算法签名的APK,获取./META-INF/*.RSA文件
        File cerFile = getRSAFile(unPackFile);
        //针对使用DSA算法签名的APK,获取./META-INF/*.DSA文件
        if (cerFile == null )
            cerFile = getDSAFile(unPackFile);
        FileInputStream input = null;
        try {
            input = new FileInputStream(cerFile);
            PKCS7 pkcs7 = new PKCS7(input);
            Certificate[] certs = pkcs7.getCertificates();
            String eggPainSign = (new String(BytetoChars(certs[certs.length - 1].getEncoded())));
            String eggPainMd5 = MD5.toMD5(eggPainSign.getBytes());
            return eggPainMd5;
         } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (input != null) {
                try {
                    input.close();
                } catch (IOException e) {
                }
            }
        }
        return null;
    }

原理是:找到METE-INF下存储签名的文件(可能是RSA或者RSA结尾),生成Certificate[]对象,取起MD5即可;同时可以发现,Signature对象其实就是在Certificate基础上做了一层封装,其中BytetoChars方法如下:

    /**
     * @param mSignature
     * @return
     */
    private static char[] BytetoChars(byte[] mSignature) {
        byte[] sig = mSignature;
        final int N = sig.length;
        final int N2 = N * 2;
        char[] text = new char[N2];
        for (int j = 0; j<N; j++) {
            byte v = sig[j];
            int d = (v >> 4)&0xf;
            text[j * 2] = (char) (d>=10 ? ('a' + d - 10) : ('0' + d));
            d = v&0xf;
            text[j * 2 + 1] = (char) (d>=10 ? ('a' + d - 10) : ('0' + d));
        }
        return text;
    }



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值