1. 程式人生 > >Android APK 簽名校驗

Android APK 簽名校驗

非對稱加密演算法

非對稱加密演算法需要兩個金鑰:公開金鑰(簡稱公鑰)和私有金鑰(簡稱私鑰)。公鑰與私鑰是一對,如果用公鑰對資料進行加密,只有用對應的私鑰才能解密;如果用私鑰對資料進行加密,那麼只有用對應的公鑰才能解密。因為加密和解密使用的是兩個不同的金鑰,所以這種演算法叫作非對稱加密演算法。

非對稱加密演算法是數字簽名和數字證書的基礎,大家非常熟悉的RSA就是非對稱加密演算法的一種實現。

訊息摘要演算法

訊息摘要演算法(Message Digest Algorithm)是一種能產生特殊輸出格式的演算法,其原理是根據一定的運算規則對原始資料進行某種形式的資訊提取,被提取出的資訊就被稱作原始資料的訊息摘要。著名的摘要演算法有

RSA公司的MD5演算法和SHA-1演算法及其大量的變體。


數字簽名及數字證書

數字證書

1.證書釋出機構

2.證書的有效期3

3.訊息傳送方的公鑰

4.證書的所有者

5.數字簽名所使用的演算法

6.數字簽名

APK簽名前

APK簽名後

META-INF資料夾


其實,在Android的原始碼裡包含了一個工具,可以對apk檔案進行簽名,具體的程式碼位置在build\tools\signapk目錄下,通過分析其中的SignApk.Java檔案,可以大致瞭解簽名的過程。其流程大致有如下幾步:

1)開啟待簽名的apk檔案(由於apk其實是一個用zip壓縮的檔案,其實就是用zip解壓整個apk檔案),逐一遍歷裡面的所有條目,如果是目錄就跳過,如果是一個檔案,就用SHA1(或者SHA256)訊息摘要演算法提取出該檔案的摘要然後進行BASE64編碼後,作為“SHA1-Digest”屬性的值寫入到MANIFEST.MF檔案中的一個塊中。該塊有一個“Name”屬性,其值就是該檔案在apk包中的路徑。


2)計算這個MANIFEST.MF檔案的整體SHA1值,再經過BASE64編碼後,記錄在CERT.SF主屬性塊(在檔案頭上)的“SHA1-Digest-Manifest”屬性值值下。

然後,再逐條計算MANIFEST.MF檔案中每一個塊的SHA1,並經過BASE64編碼後,記錄在CERT.SF中的同名塊中,屬性的名字是“SHA1-Digest”。


3)把之前生成的 CERT.SF檔案, 用私鑰計算出簽名, 然後將簽名以及包含公鑰資訊的數字證書一同寫入  CERT.RSA  中儲存。CERT.RSA是一個滿足PKCS7格式的檔案,可以通過openssl工具來檢視簽名證書的資訊。在Ubuntu或者在Windows上使用Cygwin,敲入以下命令:

  1. openssl pkcs7 -inform DER -in CERT.RSA -noout -print_certs –text  
可以得到如下輸出:

下面我們來看看,如果apk檔案被篡改後會發生什麼。

首先,如果你改變了apk包中的任何檔案,那麼在apk安裝校驗時,改變後的檔案摘要資訊與MANIFEST.MF的檢驗資訊不同,於是驗證失敗,程式就不能成功安裝。

其次,如果你對更改的過的檔案相應的算出新的摘要值,然後更改MANIFEST.MF檔案裡面對應的屬性值,那麼必定與CERT.SF檔案中算出的摘要值不一樣,照樣驗證失敗。

最後,如果你還不死心,繼續計算MANIFEST.MF的摘要值,相應的更改CERT.SF裡面的值,那麼數字簽名值必定與CERT.RSA檔案中記錄的不一樣,還是失敗。

那麼能不能繼續偽造數字簽名呢?不可能,因為沒有數字證書對應的私鑰。

所以,如果要重新打包後的應用程式能再Android裝置上安裝,必須對其進行重簽名。


我們還是用前面的例子分析,假設簽名後,apk檔案中多了一個META-INF目錄,裡面有三個檔案,分別是MANIFEST.MFCERT.SFCERT.RSA


通過前面的分析,我們可以知道,MANIFEST.MF中記錄的是apk中所有檔案的摘要值;CERT.SF中記錄的是對MANIFEST.MF的摘要值,包括整個檔案的摘要,還有檔案中每一項的摘要;而CERT.RSA中記錄的是對CERT.SF檔案的簽名,以及簽名的公鑰。

大家知道,Android平臺上所有應用程式安裝都是由PackageManangerService(程式碼位於frameworks\base\services\core\java\com\android\server\pm\PackageManagerService.java)來管理的,Android的安裝流程非常複雜,與簽名驗證相關的步驟位於installPackageLI函式中:

總結

1)Android應用程式簽名只是用來解決釋出的應用不被別人篡改的,其並不會對應用程式本身進行加密,這點不同於Windows Phone和iOS。

2)Android並不要求所有應用程式的簽名證書都由可信任CA的根證書籤名,通過這點保證了其生態系統的開放性,所有人都可以用自己生成的證書對應用程式簽名。

3)如果想修改一個已經發布的應用程式,哪怕是修改一張圖片,都必須對其進行重新簽名。但是,籤原始應用的私鑰一般是拿不到的(肯定在原始應用程式開發者的手上,且不可能公佈出去),所以只能用另外一組公私鑰對,生成一個新的證書,對重打包的應用進行簽名。所以重打包的apk中所帶證書的公鑰肯定和原始應用不一樣。同時,在手機上如果想安裝一個應用程式,應用程式安裝器會先檢查相同包名的應用是否已經被安裝過,如果已經安裝過,會繼續判斷已經安裝的應用和將要安裝的應用,其所攜帶的數字證書中的公鑰是否一致。如果相同,則繼續安裝;而如果不同,則會提示使用者先解除安裝前面已安裝的應用。

到這裡,apk安裝時的簽名驗證過程都已經分析完了,來總結一下:

  1. 所有有關apk檔案的簽名驗證工作都是在JarVerifier裡面做的,一共分成三步;
  2. JarVeirifer.verifyCertificate主要做了兩步。首先,使用證書檔案(在META-INF目錄下,以.DSA.RSA或者.EC結尾的檔案)檢驗簽名檔案(在META-INF目錄下,和證書檔案同名,但副檔名為.SF的檔案)是沒有被修改過的。然後,使用簽名檔案,檢驗MANIFEST.MF檔案中的內容也沒有被篡改過;
  3. JarVerifier.VerifierEntry.verify做了最後一步驗證,即保證apk檔案中包含的所有檔案,對應的摘要值與MANIFEST.MF檔案中記錄的一致。