Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android的APK應用簽名機制以及讀取簽名的方法

Android的APK應用簽名機制以及讀取簽名的方法

編輯:關於Android編程

發布過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); 
  } 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved