Android的APK应用签名机制以及读取签名的方法

发布过Android应用的朋友们应该都知道,Android APK的发布是需要签名的。签名机制在Android应用和框架中有着十分重要的作用。例如,Android系统禁止更新安装签名不一致的APK;如果应用需要使用system权限,必须保证APK签名与Framework签名一致,等等。

什么是签名
首先我们得知道什么是摘要,摘要是指采用单向Hash函数对数据进行计算生成的固定长度的Hash值,摘要算法有Md5,Sha1等,Md5生成的Hash值是128位的数字,即16个字节,用十六进制表示是32个字符,Sha1生成的Hash值是160位的数字,即20个字节,用十六进制表示是40个字符。我们是不能通过摘要推算出用于计算摘要的数据,如果修改了数据,那么它的摘要一定会变化(其实这句话并不正确,只是很难正好找到不同的数据,而他们的摘要值正好相等)。摘要经常用于验证数据的完整性,很多下载网站都会列出下载文件的md5值或者sha1值。
摘要和签名没有任何关系,网上常常将摘要和签名混为一谈,这是错误的。签名和数字签名是同一个概念,是指信息的发送者用自己的私钥对消息摘要加密产生一个字符串,加密算法确保别人无法伪造生成这段字符串,这段数字串也是对信息的发送者发送信息真实性的一个有效证明。其他发送者用他们的私钥对同一个消息摘要加密会得到不同的签名,接收者只有使用发送者签名时使用的私钥对应的公钥解密签名数据才能得到消息摘要,否则得到的不是正确的消息摘要。
数字签名是非对称密钥加密技术+数字摘要技术的结合。
数字签名技术是将信息摘要用发送者的私钥加密,和原文以及公钥一起传送给接收者。接收者只有用发送者的公钥才能解密被加密的信息摘要,然后接收者用相同的Hash函数对收到的原文产生一个信息摘要,与解密的信息摘要做比对。如果相同,则说明收到的信息是完整的,在传输过程中没有被修改;不同则说明信息被修改过,因此数字签名能保证信息的完整性。并且由于只有发送者才有加密摘要的私钥,所以我们可以确定信息一定是发送者发送的。
另外还需要理解一个概念:数字证书。数字证书是一个经证书授权中心数字签名的包含公钥及其拥有者信息的文件。数字证书的格式普遍采用的是X.509V3国际标准,一个标准的X.509数字证书包含以下一些内容:证书的版本信息:
1)证书的序列号,每个证书都有一个唯一的证书序列号;
2)证书所使用的签名算法;
3)证书的发行机构名称,命名规则一般采用X.500格式;
4)证书的有效期,通用的证书一般采用UTC时间格式,它的计时范围为1950-2049;
5)证书所有人的名称,命名规则一般采用X.500格式;
6)证书所有人的公开密钥;
7)证书发行者对证书的签名。
CERT.RSA包含了数字签名以及开发者的数字证书。CERT.RSA里的数字签名是指对CERT.SF的摘要采用私钥加密后的数据,Android系统安装apk时会对CERT.SF计算摘要,然后使用CERT.RSA里的公钥对CERT.RSA里的数字签名解密得到一个摘要,比较这两个摘要便可知道该apk是否有正确的签名,也就说如果其他人修改了apk并没有重新签名是会被检查出来的。
需注意Android平台的证书是自签名的,也就说不需要权威机构签发,数字证书的发行机构和所有人是相同的,都是开发者自己,开发者生成公私钥对后不需要提交到权威机构进行校验。

读取签名
某些时候需要获取某个特定的apk(已安装或者未安装)的签名信息,如程序自检测,可信赖的第三方检测(应用市场),系统限定安装 
对此,有两种实现方法 
可以使用Java自带的API(主要用到的为JarFile,JarEntry,Certificate)进行获取,还有一种方法是使用系统隐藏的API PackageParser,通过反射来使用对应的API. 
但是由于安卓系统的分裂版本过多,并且不同厂商进行的修改很多,依赖反射隐藏API的方法并不能保证兼容性和通用性,因此推荐使用JAVA自带API进行获取:


  /**
   * 从APK中读取签名
   * @param file
   * @return
   * @throws IOException
   */
  private static List<String> getSignaturesFromApk(File file) throws IOException {
    List<String> signatures=new ArrayList<String>();
    JarFile jarFile=new JarFile(file);
    try {
      JarEntry je=jarFile.getJarEntry("AndroidManifest.xml");
      byte[] readBuffer=new byte[8192];
      Certificate[] certs=loadCertificates(jarFile, je, readBuffer);
      if(certs != null) {
        for(Certificate c: certs) {
          String sig=toCharsString(c.getEncoded());
          signatures.add(sig);
        }
      }
    } catch(Exception ex) {
    }
    return signatures;
  } 

 /**
   * 加载签名
   * @param jarFile
   * @param je
   * @param readBuffer
   * @return
   */
  private static Certificate[] loadCertificates(JarFile jarFile, JarEntry je, byte[] readBuffer) {
    try {
      InputStream is=jarFile.getInputStream(je);
      while(is.read(readBuffer, 0, readBuffer.length) != -1) {
      }
      is.close();
      return je != null ? je.getCertificates() : null;
    } catch(IOException e) {
    }
    return null;
  } 

/**
   * 将签名转成转成可见字符串
   * @param sigBytes
   * @return
   */
  private static String toCharsString(byte[] sigBytes) {
    byte[] sig=sigBytes;
    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 new String(text);
  }
(0)

相关推荐

  • Eclipse下配置Ant脚本并自动打包带签名的Android apk

    eclipse虽然用的比较少,但是在一些古老的项目上还会用到滴,其中最麻烦的事情就是打带签名包的问题,不太方便,下面通过本文给大家记录下配置ant,自动打包带签名apk的过程,作为备份.(PC环境为MAC) 1,第一步得安ant,下载对应安装包,解压后配置环境变量: export ANT_HOME="/Users/yanzi/work/apache-ant-1.9.4" export PATH=${PATH}:${ANT_HOME}/bin 通过which ant检查是否安装成功. 2

  • Android 使用jarsigner给apk签名的方法详细介绍

    Android 使用jarsigner给apk签名的方法详细介绍 工作中APP功能完成以后往往需要往应用商店提交一些内容,如商店中存在本公司别的人员提交的APP,往往需要进行认领,应用商店会让开发者下载空的APK,然后使用自己APP的签名文件进行签名,认证,这里简单说一下如何使用jarsigner命令进行签名. 该arsigner命令在jdk中可以找到, 简单说明一下具体参数: -verbose:签名命令标识符. -keystore:后面跟着的是你签名使用的密钥文件(keystore)的绝对路径

  • Android简单判断某个APK是否已经安装的方法

    本文实例讲述了Android简单判断某个APK是否已经安装的方法.分享给大家供大家参考,具体如下: privateboolean isAppInstalled(String uri){ PackageManager pm = getPackageManager(); boolean installed =false; try{ pm.getPackageInfo(uri,PackageManager.GET_ACTIVITIES); installed =true; }catch(Package

  • Android APK反编译图文教程

    在学习Android开发的过程你,你往往会去借鉴别人的应用是怎么开发的,那些漂亮的动画和精致的布局可能会让你爱不释手,作为一个开发者,你可能会很想知道这些效果界面是怎么去实现的,这时,你便可以对改应用的APK进行反编译查看.下面是我参考了一些文章后简单的教程详解. (注:反编译不是让各位开发者去对一个应用破解搞重装什么的,主要目的是为了促进开发者学习,借鉴好的代码,提升自我开发水平.) 测试环境: win 7 使用工具: 我们下载地址: apktool (资源文件获取)  下载        

  • Android开发apk反编译和二次打包教程

    作为Android开发者,工作中少不了要反编译别人的apk,当然主要目的还是为了学习到更多,取彼之长,补己之短.今天就来总结一下Android反编译和二次打包的一些知识.首先声明本文的目的是为了通过例子讲解反编译和二次打包的原理和方法,继而作为后续讲解防止二次打包和App安全的依据,并不是鼓励大家去重新打包别人的App,盗取他人劳动成果. 本文首先介绍几种Android反编译工具的使用,然后实现在不需要知道源代码的情况下,仅通过修改反编译得到的smali文件实现修改apk逻辑功能的目的. And

  • Android Apk去掉签名以及重新签名的方法

    Android Apk去掉签名以及重新签名的方法 Android开发中很重要的一部就是用自己的密钥给Apk文件签名,不经过签名的Apk文件一般是无法安装的,就算装了最后也是失败. 网上流传的"勾选允许安装未知来源的应用"其实跟签不签名没啥关系,说白了就是允许安装不从电子市场上下载的应用而已. 近几日需要修改一个Apk中JNI调用的.so文件,苦于没有apk源代码,只好研究了一下签名相关的问题.当然有很多第三方工具可以做到,但其实JDK中已经提供了强大的签名工具jarsigner. 1.

  • 为Android的apk应用程序文件加壳以防止反编译的教程

    一.什么是加壳? 加壳是在二进制的程序中植入一段代码,在运行的时候优先取得程序的控制权,做一些额外的工作.大多数病毒就是基于此原理. 二.加壳作用 加壳的程序可以有效阻止对程序的反汇编分析,以达到它不可告人的目的.这种技术也常用来保护软件版权,防止被软件破解. 三.Android Dex文件加壳原理 PC平台现在已存在大量的标准的加壳和解壳工具,但是Android作为新兴平台还未出现APK加壳工具.Android Dex文件大量使用引用给加壳带来了一定的难度,但是从理论上讲,Android AP

  • Android APK优化工具Zipalign详解

    Android SDK中包含了一个用于优化APK的新工具zipalign.它提高了优化后的Applications与Android系统的交互效率(俗话:"要致富先修路",Android小组重新为Applications与Android系统之间搭建了一条高速公路),从而可以使整个系统的运行速度有了较大的提升.Android小组强烈建议开发者在发布新Apps之前使用zipalign优化工具,而且对于已经发布但不受限于系统版本的Apps,建议用优化后的APK替换现有的版本. 在下面的内容中将

  • Android应用启动另外一个apk应用的方法

    本文实例讲述了Android应用启动另外一个apk应用的方法.分享给大家供大家参考,具体如下: 在开发的过程中,经常会遇到在一个应用中启动另外一个apk应用的情况 问题的核心点在于我们要拿到第三方apk的package名称跟class名称, 如:package名称是com.funcity.taxi.passenger,class名称是com.funcity.taxi.passenger.activity.LoadActivity. 从一个apk启动到另外一个apk,当然也是通过发送intent了

  • Android获取apk签名指纹的md5值(防止重新被打包)的实现方法

    本文实例讲述了Android获取apk签名指纹的md5值以防止重新被打包的实现方法.分享给大家供大家参考,具体如下: 做个记录(这里只是Java层的签名校验,java层容易被破解,我建议apk加固下) 获取md5值来进行Apk签名校验, 可以防止apk重新被打包. 下面我说说怎么获取apk签名的md5值(有三种方法) 1.用代码获取签名指纹的md5值 /** * MD5加密 * @param byteStr 需要加密的内容 * @return 返回 byteStr的md5值 */ public

  • jarsigner重新签名apk无法安装的解决方法

    因为一些原因,要给未签名的apk重新签名,需要用到jarsigner工具,但是签名之后,apk无法安装,百思不得其解.终于找到一个解决方案,现在分享给大家: 在签名时,要加上2个参数: 复制代码 代码如下: -digestalg SHA1 -sigalg MD5withRSA 造成无法签名错误的原因,初步估计是JDK版本的问题.JDK 1.6签名没事,但是1.7会出这个问题. 完整的签名命令如下: 复制代码 代码如下: jarsigner -verbose -keystore feelyou.k

随机推荐