Android签名原理

来源:互联网 发布:微软keeper是什么软件 编辑:程序博客网 时间:2024/06/04 19:09

一、如何对一个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;    }



0 0