android签名机制

http://blog.csdn.net/feiyangxiaomi/article/details/40298155

1.android为什么要签名

所有的Android应用程序都要求开发人员用一个证书进行数字签名,anroid系统不会安装没有进行签名的由于程序。平时我们的程序可以在模拟器上安装并运行,是因为在应用程序开发期间,由于是以Debug面试进行编译的,因此ADT根据会自动用默认的密钥和证书来进行签名,而在以发布模式编译时,apk文件就不会得到自动签名,这样就需要进行手工签名。
   给apk签名可以带来以下好处:
        1. 应用程序升级:如果你希望用户无缝升级到新的版本,那么你必须用同一个证书进行签名。这是由于只有以同一个证书签名,系统才会允许安装升级的应用程序。如果你采用了不同的证书,那么系统会要求你的应用程序采用不同的包名称,在这种情况下相当于安装了一个全新的应用程序。如果想升级应用程序,签名证书要相同,包名称要相同!
        2.应用程序模块化:Android系统可以允许同一个证书签名的多个应用程序在一个进程里运行,系统实际把他们作为一个单个的应用程序,此时就可以把我们的应用程序以模块的方式进行部署,而用户可以独立的升级其中的一个模块。
        3.代码或者数据共享:Android提供了基于签名的权限机制,那么一个应用程序就可以为另一个以相同证书签名的应用程序公开自己的功能。以同一个证书对多个应用程序进行签名,利用基于签名的权限检查,你就可以在应用程序间以安全的方式共享代码和数据了。

不同的应用程序之间,想共享数据,或者共享代码,那么要让他们运行在同一个进程中,而且要让他们用相同的证书签名。

2.签名的方法

参考:签名的方法 ,这里就不详述签名的方法

3.签名机制的原理

3.1基本知识

消息摘要 -Message Digest
简称摘要,请看英文翻译,是摘要,不是签名,网上几乎所有APK签名分析的文章都混淆了这两个概念。简单的说消息摘要就是在消息数据上,执行一个单向的Hash函数,生成一个固定长度的Hash值,这个Hash值即是消息摘要也称为数字指纹,消息摘要有以下特点:
1. 通过摘要无法推算得出消息本身
2. 如果修改了消息,那么摘要一定会变化(实际上,由于长明文生成短摘要的Hash必然会产生碰撞),所以这句话并不准确,我们可以改为:很难找到一种模式,修改了消息,而它的摘要不会变化(抗冲突性)。

消息摘要的这种特性,很适合来验证数据的完整性,比如在网络传输过程中下载一个大文件BigFile,我们会同时从网络下载BigFile和BigFile.md5,BigFile.md5保存BigFile的摘要,我们在本地生成BigFile的消息摘要,和BigFile.md5比较,如果内容相同,则表示下载过程正确。
注意,消息摘要只能保证消息的完整性,并不能保证消息的不可篡改性。

MD5/SHA-0 SHA-1
这些都是摘要生成算法,和签名没有关系。如果非要说他们和签名有关系,那就是签名是要借助于摘要技术。

数字签名 - Signature
数字签名,百度百科对数字签名有非常清楚的介绍。数字签名就是信息的发送者用自己的私钥对消息摘要加密产生一个字符串,加密算法确保别人无法伪造生成这段字符串,这段数字串也是对信息的发送者发送信息真实性的一个有效证明。数字签名是 非对称密钥加密技术 + 数字摘要技术 的结合。

数字签名技术是将信息摘要用发送者的私钥加密,与原文一起传送给接收者。接收者只有用发送者的公钥才能解密被加密的信息摘要,然后接收者用相同的Hash函数对收到的原文产生一个信息摘要,与解密的信息摘要做比对。如果相同,则说明收到的信息是完整的,在传输过程中没有被修改;不同则说明信息被修改过,因此数字签名能保证信息的完整性。并且由于只有发送者才有加密摘要的私钥,所以我们可以确定信息一定是发送者发送的。

数字证书 - Certificate
数字证书是一个经证书授权 中心数字签名的包含公开密钥拥有者信息以及公开密钥的文件。CERT.RSA包含了一个数字签名以及一个数字证书。
需要注意的是Android APK中的CERT.RSA证书是自签名的,并不需要这个证书是第三方权威机构发布或者认证的,用户可以在本地机器自行生成这个自签名证书。

3.2 Android签名分析

我们将DF_SDM_1008.apk(自己任选)文件改为DF_SDM_1008.zip文件,打开DF_SDM_1008.zip文件,如图1所示。

图1 DF_SDM_1008.zip文件

1. META-INF\ (注:签名后的信息);
2. res\ (注:存放资源文件的目录) ;
3. AndroidManifest.xml (注:程序全局配置文件) ;
4. classes.dex (注:Dalvik字节码);
5. resources.arsc (注:编译后的二进制资源文件)。

接下来针对META-INF\文件进行分析。

3.3META-INF\文件

META-INF\文件中有三个文件,分别是MANIFEST.MF, CERT.SF, CERT.RSA,如图2所示。

现在有一个问题就是,三个文件怎么产生的的——签名产生的,第二个问题签名是怎么做的呢?这里Android提供了APK的签名工具signapk,通过xxx.keystore(java的密钥库、用来进行通信加密用的、比如数字签名。keystore就是用来保存密钥对的,比如公钥和私钥)提供的信息,对APK进行签名,生成的META-INF\文件,参考文章4。

1.MANIFEST.MF文件

先看一下源代码

[java] view plaincopy

  1. // MANIFEST.MF
  2. Manifest manifest = addDigestsToManifest(inputJar);
  3. je = new JarEntry(JarFile.MANIFEST_NAME);
  4. je.setTime(timestamp);
  5. outputJar.putNextEntry(je);
  6. manifest.write(outputJar);

[java] view plaincopy

  1. /** Add the SHA1 of every file to the manifest, creating it if necessary. */
  2. private static Manifest addDigestsToManifest(JarFile jar)
  3. throws IOException, GeneralSecurityException {
  4. Manifest input = jar.getManifest();
  5. Manifest output = new Manifest();
  6. Attributes main = output.getMainAttributes();
  7. if (input != null) {
  8. main.putAll(input.getMainAttributes());
  9. } else {
  10. main.putValue("Manifest-Version", "1.0");
  11. main.putValue("Created-By", "1.0 (Android SignApk)");
  12. }
  13. <span style="white-space:pre">    </span>......
  14. for (JarEntry entry: byName.values()) {
  15. String name = entry.getName();
  16. if (!entry.isDirectory() && !name.equals(JarFile.MANIFEST_NAME) &&
  17. !name.equals(CERT_SF_NAME) && !name.equals(CERT_RSA_NAME) &&
  18. (stripPattern == null ||
  19. !stripPattern.matcher(name).matches())) {
  20. InputStream data = jar.getInputStream(entry);
  21. while ((num = data.read(buffer)) > 0) {
  22. md.update(buffer, 0, num);
  23. }
  24. Attributes attr = null;
  25. if (input != null) attr = input.getAttributes(name);
  26. attr = attr != null ? new Attributes(attr) : new Attributes();
  27. attr.putValue("SHA1-Digest", base64.encode(md.digest()));
  28. output.getEntries().put(name, attr);
  29. }
  30. }
  31. return output;
  32. }

遍历APK包中的每一个文件,利用SHA1算法生成这些文件的摘要信息。

验证是所有文件使用的SHA1算法

1.安装hashTab工具
2.打开MANIFEST.MF文件

举个例子:

[html] view plaincopy

  1. Name: AndroidManifest.xml
  2. SHA1-Digest: Zovq4AVMcCjFkILZLlHgmeOLvnU=

其中找到文件中的AndroidManifest.xml文件,查看其对应的hash值,如图3所示。

这里取出16进制的668BEAE0054C7028C59082D92E51E099E38BBE75,将16进制通过在线转码网站:hex to base64转化为对应的base64编码,看见“Zovq4AVMcCjFkILZLlHgmeOLvnU=”与记录信息相对的。

2.CERT.SF文件

先看一下源码

[html] view plaincopy

  1. // CERT.SF
  2. Signature signature = Signature.getInstance("SHA1withRSA");
  3. signature.initSign(privateKey);
  4. je = new JarEntry(CERT_SF_NAME);
  5. je.setTime(timestamp);
  6. outputJar.putNextEntry(je);
  7. writeSignatureFile(manifest,
  8. new SignatureOutputStream(outputJar, signature));

[html] view plaincopy

  1. /** Write a .SF file with a digest of the specified manifest. */
  2. private static void writeSignatureFile(Manifest manifest, SignatureOutputStream out)
  3. throws IOException, GeneralSecurityException {
  4. Manifest sf = new Manifest();
  5. Attributes main = sf.getMainAttributes();
  6. main.putValue("Signature-Version", "1.0");
  7. main.putValue("Created-By", "1.0 (Android SignApk)");
  8. BASE64Encoder base64 = new BASE64Encoder();
  9. MessageDigest md = MessageDigest.getInstance("SHA1");
  10. PrintStream print = new PrintStream(
  11. new DigestOutputStream(new ByteArrayOutputStream(), md),
  12. true, "UTF-8");
  13. // Digest of the entire manifest
  14. manifest.write(print);
  15. print.flush();
  16. main.putValue("SHA1-Digest-Manifest", base64.encode(md.digest()));
  17. Map<String, Attributes> entries = manifest.getEntries();
  18. for (Map.Entry<String, Attributes> entry : entries.entrySet()) {
  19. // Digest of the manifest stanza for this entry.
  20. print.print("Name: " + entry.getKey() + "\r\n");
  21. for (Map.Entry<Object, Object> att : entry.getValue().entrySet()) {
  22. print.print(att.getKey() + ": " + att.getValue() + "\r\n");
  23. }
  24. print.print("\r\n");
  25. print.flush();
  26. Attributes sfAttr = new Attributes();
  27. sfAttr.putValue("SHA1-Digest", base64.encode(md.digest()));
  28. sf.getEntries().put(entry.getKey(), sfAttr);
  29. }
  30. <span style="white-space:pre">    </span>//签名信息在上面并没有使用的到
  31. sf.write(out);
  32. // A bug in the java.util.jar implementation of Android platforms
  33. // up to version 1.6 will cause a spurious IOException to be thrown
  34. // if the length of the signature file is a multiple of 1024 bytes.
  35. // As a workaround, add an extra CRLF in this case.
  36. if ((out.size() % 1024) == 0) {
  37. out.write(‘\r‘);
  38. out.write(‘\n‘);
  39. }
  40. }

虽然writeSignatureFile字面上看起来是写签名文件,但是CERT.SF的生成和私钥没有一分钱的关系,实际上也不应该有一分钱的关系,这个文件自然不保存任何签名内容。CERT.SF中保存的是MANIFEST.MF的摘要值(第一项),

[html] view plaincopy

  1. Signature-Version: 1.0
  2. Created-By: 1.0 (Android)
  3. SHA1-Digest-Manifest: nGpBbfOirA4fsY0pn0dBONop5bQ=

以及MANIFEST.MF中每一个摘要项的摘要值。我也没搞清楚为什么要引入CERT.SF,实际上我也觉得签名完全可以用MANIFEST.MF生成。
验证所有的摘要都是MANIFEST.MF条目
首先:对应MANIFEST.MF文件,对应的消息摘要为SHA1-Digest-Manifest: nGpBbfOirA4fsY0pn0dBONop5bQ=,对应的实际消息摘要如图4所示。

图4 MANIFEST.MF消息摘要和对应的base64编码

其次:验证条目的消息摘要,根据条目消息摘要的算法知道内容格式为SHA1("Name: filename"+CR+LF+"SHA1-Digest: "+SHA1(file_content)+CR+LF+CR+LF)

我先把CERT.SF中的一项取出来,然后验证,取出

[html] view plaincopy

  1. Name: AndroidManifest.xml
  2. SHA1-Digest: PJblxooLyYkHHlr/0lKZkk2DkM0=

在将MANIFEST.MF条目取出,保存为“新建文本文档.txt”,查看对应的消息摘要,并将其转换为base64编码,如图5所示。

图5 新建文本文档.txt的消息摘要和对应的base64编码

这里完成了对CERT.SF的验证。

3.CERT.RSA文件

代码为

[html] view plaincopy

  1. // CERT.RSA
  2. je = new JarEntry(CERT_RSA_NAME);
  3. je.setTime(timestamp);
  4. outputJar.putNextEntry(je);
  5. writeSignatureBlock(signature, publicKey, outputJar);

[html] view plaincopy

  1. /** Write a .RSA file with a digital signature. */
  2. private static void writeSignatureBlock(
  3. Signature signature, X509Certificate publicKey, OutputStream out)
  4. throws IOException, GeneralSecurityException {
  5. SignerInfo signerInfo = new SignerInfo(
  6. new X500Name(publicKey.getIssuerX500Principal().getName()),
  7. publicKey.getSerialNumber(),
  8. AlgorithmId.get("SHA1"),
  9. AlgorithmId.get("RSA"),
  10. signature.sign());
  11. PKCS7 pkcs7 = new PKCS7(
  12. new AlgorithmId[] { AlgorithmId.get("SHA1") },
  13. new ContentInfo(ContentInfo.DATA_OID, null),
  14. new X509Certificate[] { publicKey },
  15. new SignerInfo[] { signerInfo });
  16. pkcs7.encodeSignedData(out);
  17. }

这个文件保存了签名和公钥证书。签名的生成一定会有私钥参与,签名用到的信息摘要就是CERT.SF内容。
signature这个数据会作为签名用到的摘要,writeSignatureBlock函数用privateKey对signature加密生成签名,然后把签名和公钥证书一起保存到CERT.RSA中。
最终保存在CERT.RSA中的是CERT.SF的数字签名,签名使用privateKey生成的,签名算法会在publicKey中定义。同时还会把publicKey存放在CERT.RSA中,也就是说CERT.RSA包含了签名和签名用到的证书。并且要求这个证书是自签名的。
提取CERT.RSA信息

参考有RSA公钥信息、subject信息、对应的签名信息。

[html] view plaincopy

  1. Certificate:
  2. Data:
  3. Version: 3 (0x2)
  4. Serial Number: 1281971851 (0x4c69568b)
  5. Signature Algorithm: sha1WithRSAEncryption
  6. Issuer: CN=Michael Liu
  7. Validity
  8. Not Before: Aug 16 15:17:31 2010 GMT
  9. Not After : Aug 10 15:17:31 2035 GMT
  10. Subject: CN=Michael Liu
  11. Subject Public Key Info:
  12. Public Key Algorithm: rsaEncryption
  13. RSA Public Key: (1024 bit)
  14. Modulus (1024 bit):
  15. 00:8d:04:84:a2:1e:c6:56:39:f2:cd:a6:f0:48:a5:
  16. f7:5e:71:8f:e1:a8:af:a7:dc:66:92:a2:b9:cf:da:
  17. 0f:32:42:ce:83:fe:bc:e1:4f:0a:fd:d9:a8:b3:73:
  18. f4:ff:97:15:17:87:d6:d0:3c:da:01:fc:11:40:7d:
  19. 04:da:31:cc:cd:da:d0:e7:7b:e3:c1:84:30:9f:21:
  20. 93:95:20:48:b1:2d:24:02:d2:b9:3c:87:0d:fa:b8:
  21. e1:b1:45:f4:8d:90:0a:3b:9d:d8:8a:9a:96:d1:51:
  22. 23:0e:8e:c4:09:68:7d:95:be:c6:42:e9:54:a1:5c:
  23. 5d:3f:25:d8:5c:c3:42:73:21
  24. Exponent: 65537 (0x10001)
  25. Signature Algorithm: sha1WithRSAEncryption
  26. 78:3c:6b:ef:71:70:55:68:28:80:4d:f8:b5:cd:83:a9:01:21:
  27. 2a:c1:e4:96:ad:bc:5f:67:0c:cd:c3:34:51:6d:63:90:a9:f9:
  28. d5:5e:c7:ef:34:43:86:7d:68:e1:99:87:92:86:34:91:6d:67:
  29. 6d:b2:22:e9:5e:28:aa:e8:05:52:04:6e:4e:d4:7f:0f:b0:d6:
  30. 28:f5:2b:11:38:d5:15:cb:e3:e4:c9:99:23:c1:84:4f:ce:69:
  31. e9:b1:59:7b:8e:30:01:1c:e1:92:ee:0d:54:61:29:f5:8e:9e:
  32. 42:72:26:2b:aa:c7:af:d9:c9:d1:85:95:8e:4c:8d:5c:77:c5:
  33. ce:4e

参考文章:

1.Android为什么要为app签名

2.签名的方法

3.消息摘要、数字签名、数字证书

4.signApk项目

5.提取CERT.RSA中的公钥和签名信息

时间: 2024-11-06 18:14:54

android签名机制的相关文章

Android签名机制:生成keystore、签名、查看签名信息

Android独有的安全机制,除了权限机制外,另外一个就是签名机制了.签名机制主要用在以下两个主要场合起到其作用:升级App和权限检查. 升级App 用户在升级一款已经安装过的App时,如果程序的修改来自于同一来源,则允许升级安装,否则会提示签名不一致无法安装的提示. 权限检查 我曾在Android Permission权限机制的具体使用一文中提过,对于申请权限的  protection level 为 signature 或者 signatureOrSystem 的,会检查权限申请者和权限声明

Android签名机制之---签名过程具体解释

一.前言 又是过了好长时间,没写文章的双手都有点难受了.今天是圣诞节,还是得上班.由于前几天有一个之前的同事,在申请微信SDK的时候,遇到签名的问题,问了我一下,结果把我难倒了..我说Android中的签名大家都会熟悉的,就是为了安全,不让别人改动你的apk,可是我们真正的有了解多少呢?所以准备两篇文章好好介绍一下Android中签名机制. 在说道Android签名之前,我们须要了解的几个知识点 1.数据摘要(数据指纹).签名文件,证书文件 2.jarsign工具签名和signapk工具签名 3

[转载] Android签名机制之—签名过程详解

本文转载自: http://www.wjdiankong.cn/android%E7%AD%BE%E5%90%8D%E6%9C%BA%E5%88%B6%E4%B9%8B-%E7%AD%BE%E5%90%8D%E8%BF%87%E7%A8%8B%E8%AF%A6%E8%A7%A3/ 一.前言 又是过了好长时间,没写文章的双手都有点难受了.今天是圣诞节,还是得上班.因为前几天有一个之前的同事,在申请微信SDK的时候,遇到签名的问题,问了我一下,结果把我难倒了..我说Android中的签名大家都会熟悉

Android签名机制之---签名过程详解

一.前言 又是过了好长时间,没写文章的双手都有点难受了.今天是圣诞节,还是得上班.因为前几天有一个之前的同事,在申请微信SDK的时候,遇到签名的问题,问了我一下,结果把我难倒了..我说Android中的签名大家都会熟悉的,就是为了安全,不让别人修改你的apk,但是我们真正的有了解多少呢?所以准备两篇文章好好介绍一下Android中签名机制. 在说道Android签名之前,我们需要了解的几个知识点 1.数据摘要(数据指纹).签名文件,证书文件 2.jarsign工具签名和signapk工具签名 3

[转载] Android签名机制之—签名验证过程详解

本文转载自: http://www.wjdiankong.cn/android%E7%AD%BE%E5%90%8D%E6%9C%BA%E5%88%B6%E4%B9%8B-%E7%AD%BE%E5%90%8D%E9%AA%8C%E8%AF%81%E8%BF%87%E7%A8%8B%E8%AF%A6%E8%A7%A3/ 一.前言 今天是元旦,也是Single Dog的嚎叫之日,只能写博客来祛除寂寞了,今天我们继续来看一下Android中的签名机制的姊妹篇:Android中是如何验证一个Apk的签名.

Android签名机制之---签名验证过程具体解释

一.前言 今天是元旦,也是Single Dog的嚎叫之日,仅仅能写博客来祛除寂寞了,今天我们继续来看一下Android中的签名机制的姊妹篇:Android中是怎样验证一个Apk的签名. 在前一篇文章中我们介绍了,Android中是怎样对程序进行签名的,不了解的同学能够转战: http://blog.csdn.net/jiangwei0910410003/article/details/50402000 当然在了解我们今天说到的知识点,这篇文章也是须要了解的,不然会有些知识点有些困惑的. 二.知识

Android 签名机制

1.如何对APK签名 (1).创建数字证书,android123.keystore keytool -genkey -alias android123.keystore -keyalg RSA -validity 20000 -keystore android123.keystore keytool工具是Java JDK自带的证书工具 -genkey参数表示:要生成一个证书(版权.身份识别的安全证书) -alias参数表示:证书有别名,-alias android123.keystore表示证书

Android 安全机制(1)uid 、 gid 与 pid

1.概述 Android 安全机制来源于Linux,并且以Linux权限管理为基础,要了解Android的安全机制,需要从linux中的安全机制了解开始,而用户的权限管理又是linux安全机制的最基本的一个组成 2.linux中的用户(UID).组(GID).进程(PID) 在 Linux 中,一个用户 UID 标示一个给定用户.Linux系统中的用户(UID)分为3类,即普通用户.根用户.系统用户. 普通用户是指所有使用Linux系统的真实用户,这类用户可以使用用户名及密码登录系统.Linux

Android安全机制(2) Android Permission权限控制机制

1.概述 Android 是一个权限分离的系统 . 这是利用 Linux 已有的权限管理机制,通过为每一个 Application 分配不同的 uid 和 gid , 从而使得不同的 Application 之间的私有数据和访问( native 以及 java 层通过这种 sandbox 机制,都可以)达到隔离的目的 . 与此 同时, Android 还 在此基础上进行扩展,提供了 permission 机制,它主要是用来对 Application 可以执行的某些具体操作进行权限细分和访问控制,