欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Android的APK應(yīng)用簽名機(jī)制以及讀取簽名的方法

 更新時(shí)間:2016年02月23日 14:22:05   作者:Cloud Chou  
這篇文章主要介紹了Android的APK應(yīng)用簽名機(jī)制以及讀取簽名的方法,這里作者推薦使用Java自帶的API進(jìn)行APK簽名的讀取,需要的朋友可以參考下

發(fā)布過(guò)Android應(yīng)用的朋友們應(yīng)該都知道,Android APK的發(fā)布是需要簽名的。簽名機(jī)制在Android應(yīng)用和框架中有著十分重要的作用。例如,Android系統(tǒng)禁止更新安裝簽名不一致的APK;如果應(yīng)用需要使用system權(quán)限,必須保證APK簽名與Framework簽名一致,等等。

什么是簽名
首先我們得知道什么是摘要,摘要是指采用單向Hash函數(shù)對(duì)數(shù)據(jù)進(jìn)行計(jì)算生成的固定長(zhǎng)度的Hash值,摘要算法有Md5,Sha1等,Md5生成的Hash值是128位的數(shù)字,即16個(gè)字節(jié),用十六進(jìn)制表示是32個(gè)字符,Sha1生成的Hash值是160位的數(shù)字,即20個(gè)字節(jié),用十六進(jìn)制表示是40個(gè)字符。我們是不能通過(guò)摘要推算出用于計(jì)算摘要的數(shù)據(jù),如果修改了數(shù)據(jù),那么它的摘要一定會(huì)變化(其實(shí)這句話并不正確,只是很難正好找到不同的數(shù)據(jù),而他們的摘要值正好相等)。摘要經(jīng)常用于驗(yàn)證數(shù)據(jù)的完整性,很多下載網(wǎng)站都會(huì)列出下載文件的md5值或者sha1值。
摘要和簽名沒(méi)有任何關(guān)系,網(wǎng)上常常將摘要和簽名混為一談,這是錯(cuò)誤的。簽名和數(shù)字簽名是同一個(gè)概念,是指信息的發(fā)送者用自己的私鑰對(duì)消息摘要加密產(chǎn)生一個(gè)字符串,加密算法確保別人無(wú)法偽造生成這段字符串,這段數(shù)字串也是對(duì)信息的發(fā)送者發(fā)送信息真實(shí)性的一個(gè)有效證明。其他發(fā)送者用他們的私鑰對(duì)同一個(gè)消息摘要加密會(huì)得到不同的簽名,接收者只有使用發(fā)送者簽名時(shí)使用的私鑰對(duì)應(yīng)的公鑰解密簽名數(shù)據(jù)才能得到消息摘要,否則得到的不是正確的消息摘要。
數(shù)字簽名是非對(duì)稱密鑰加密技術(shù)+數(shù)字摘要技術(shù)的結(jié)合。
數(shù)字簽名技術(shù)是將信息摘要用發(fā)送者的私鑰加密,和原文以及公鑰一起傳送給接收者。接收者只有用發(fā)送者的公鑰才能解密被加密的信息摘要,然后接收者用相同的Hash函數(shù)對(duì)收到的原文產(chǎn)生一個(gè)信息摘要,與解密的信息摘要做比對(duì)。如果相同,則說(shuō)明收到的信息是完整的,在傳輸過(guò)程中沒(méi)有被修改;不同則說(shuō)明信息被修改過(guò),因此數(shù)字簽名能保證信息的完整性。并且由于只有發(fā)送者才有加密摘要的私鑰,所以我們可以確定信息一定是發(fā)送者發(fā)送的。
另外還需要理解一個(gè)概念:數(shù)字證書。數(shù)字證書是一個(gè)經(jīng)證書授權(quán)中心數(shù)字簽名的包含公鑰及其擁有者信息的文件。數(shù)字證書的格式普遍采用的是X.509V3國(guó)際標(biāo)準(zhǔn),一個(gè)標(biāo)準(zhǔn)的X.509數(shù)字證書包含以下一些內(nèi)容:證書的版本信息:
1)證書的序列號(hào),每個(gè)證書都有一個(gè)唯一的證書序列號(hào);
2)證書所使用的簽名算法;
3)證書的發(fā)行機(jī)構(gòu)名稱,命名規(guī)則一般采用X.500格式;
4)證書的有效期,通用的證書一般采用UTC時(shí)間格式,它的計(jì)時(shí)范圍為1950-2049;
5)證書所有人的名稱,命名規(guī)則一般采用X.500格式;
6)證書所有人的公開(kāi)密鑰;
7)證書發(fā)行者對(duì)證書的簽名。
CERT.RSA包含了數(shù)字簽名以及開(kāi)發(fā)者的數(shù)字證書。CERT.RSA里的數(shù)字簽名是指對(duì)CERT.SF的摘要采用私鑰加密后的數(shù)據(jù),Android系統(tǒng)安裝apk時(shí)會(huì)對(duì)CERT.SF計(jì)算摘要,然后使用CERT.RSA里的公鑰對(duì)CERT.RSA里的數(shù)字簽名解密得到一個(gè)摘要,比較這兩個(gè)摘要便可知道該apk是否有正確的簽名,也就說(shuō)如果其他人修改了apk并沒(méi)有重新簽名是會(huì)被檢查出來(lái)的。
需注意Android平臺(tái)的證書是自簽名的,也就說(shuō)不需要權(quán)威機(jī)構(gòu)簽發(fā),數(shù)字證書的發(fā)行機(jī)構(gòu)和所有人是相同的,都是開(kāi)發(fā)者自己,開(kāi)發(fā)者生成公私鑰對(duì)后不需要提交到權(quán)威機(jī)構(gòu)進(jìn)行校驗(yàn)。

讀取簽名
某些時(shí)候需要獲取某個(gè)特定的apk(已安裝或者未安裝)的簽名信息,如程序自檢測(cè),可信賴的第三方檢測(cè)(應(yīng)用市場(chǎng)),系統(tǒng)限定安裝 
對(duì)此,有兩種實(shí)現(xiàn)方法 
可以使用Java自帶的API(主要用到的為JarFile,JarEntry,Certificate)進(jìn)行獲取,還有一種方法是使用系統(tǒng)隱藏的API PackageParser,通過(guò)反射來(lái)使用對(duì)應(yīng)的API. 
但是由于安卓系統(tǒng)的分裂版本過(guò)多,并且不同廠商進(jìn)行的修改很多,依賴反射隱藏API的方法并不能保證兼容性和通用性,因此推薦使用JAVA自帶API進(jìn)行獲取:  
  

 
  /** 
   * 從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; 
  } 
 
/** 
   * 將簽名轉(zhuǎn)成轉(zhuǎn)成可見(jiàn)字符串 
   * @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); 
  } 

相關(guān)文章

最新評(píng)論