Android APK 簽名原理

Android APK 簽名原理涉及到密碼學的加密算法、數字簽名、數字證書等基礎知識,這裏做個總結記錄。

非對稱加密

需要兩個密鑰,一個是公開密鑰,另一個是私有密鑰;一個用作加密的時候,另一個則用作解密。

其相對的加密即爲對稱加密,可以用現實世界中的例子來對比:一個傳統保管箱,開門和關門都是使用同一條鑰匙,這是對稱加密;而一個公開的郵箱,投遞口是任何人都可以寄信進去的,這可視爲公鑰;而只有郵箱主人擁有鑰匙可以打開郵箱,這就視爲私鑰。

消息摘要算法

一種能產生特殊輸出格式的算法,其原理是根據一定的運算規則對原始數據進行某種形式的信息提取,被提取出的信息就被稱作原始數據的消息摘要。著名的摘要算法有 RSA 公司的 MD5 算法和 SHA-1 算法及其大量的變體。

消息摘要算法的主要特點:

  • 變長輸入,定長輸出。即不管輸入多長,輸出永遠是相同的長度。
  • 輸入不同,輸出不同。輸入相同,輸出相同。
  • 單向、不可逆。即只能進行正向的消息摘要,而無法從摘要中恢復出任何的原始消息 。

消息摘要的作用:保證了消息的完整性。如果發送者發送的信息在傳遞過程中被篡改,那麼接受者收到信息後,用同樣的摘要算法計算其摘要,如果新摘要與發送者原始摘要不同,那麼接收者就知道消息被篡改了。

數字簽名

數字簽名是對非對稱加密和消息摘要技術的具體應用。其目的就是確保消息來源的可靠性。

消息發送者生成一對公私鑰對,將公鑰給消息的接收者。如果發送者要發送信息給接收者,會進行如下三步操作:

  • 通過消息摘要算法提取消息摘要。
  • 使用私鑰,對這個摘要加密,生成數字簽名。
  • 將原始信息和數字簽名一併發給接收者。

接收者在收到信息後通過如下兩步驗證消息來源的真僞。

  • 使用公鑰對數字簽名進行解密,得到消息的摘要,由此可以確定信息是又發送者發來的。
  • 對原始信息提取消息摘要,與解密得到的摘要對比,如果一致,說明消息在傳遞的過程中沒有被篡改。

以上的數字簽名方法的前提是,接收者必須要事先得到正確的公鑰。如果一開始公鑰就被別人篡改了,那壞人就會被你當成好人,而真正的消息發送者給你發的消息會被你視作無效的。如何保證公鑰的安全性?這就需要數字證書來解決。

數字證書

即需要一個公鑰來爲發送者的公鑰做認證,而這個公鑰的合法性又該如何保證?這個問題可以無限循環下去,無法到頭了。所以需要一個可信的機構來提供公鑰,這種機構稱爲認證機構 (Certification Authority, CA)。CA 就是能夠認定”公鑰確實屬於此人”,並能生成公鑰的數字簽名的組織或機構。

CA 用自己的私鑰,對發送者的公鑰和一些相關信息一起加密,生成"數字證書"。發送者在簽名的時候,帶上數字證書發送給接收者。接收者用 CA 的公鑰解開數字證書,就可以拿到發送者真實的公鑰了,然後就能證明"數字簽名"是否來源真實。

對於數字簽名和數字證書,可以查看阮一峯老師的文章《 數字簽名是什麼?》,講得很簡單易懂。

Android APK 簽名流程

爲了防止 APK 在傳送的過程中被第三方篡改,Google 引入了簽名機制。

簽過名的 APK 文件比未簽名的 APK 文件多了一個 META-AF 文件夾,包含以下三個文件。簽名的信息就在這三個文件中。

MANIFEST.MF
CERT.RSA
CERT.SF

APK 的簽名主要有以下幾個流程:

1、對 APK 文件夾中的文件逐一遍歷進行 SHA1 (或者 SHA256)算法計算文件的消息摘要,然後進行 BASE64 編碼後,作爲 “SHA1-Digest” 屬性的值寫入到 MANIFEST.MF 文件中的一個塊中。該塊有一個 “Name” 屬性,其值就是該文件在 APK 包中的路徑。

Manifest-Version: 1.0
Built-By: Generated-by-ADT
Created-By: Android Gradle 3.1.0

Name: AndroidManifest.xml
SHA1-Digest: 9hTSmRfzHEeQc7V2wxBbTT3DmCY=

Name: META-INF/android.arch.core_runtime.version
SHA1-Digest: BeF7ZGqBckDCBhhvlPj0xwl01dw=

Name: META-INF/android.arch.lifecycle_livedata-core.version
SHA1-Digest: BeF7ZGqBckDCBhhvlPj0xwl01dw=

2、計算這個 MANIFEST.MF 文件的整體 SHA1 值,再經過 BASE64 編碼後,記錄在 CERT.SF 主屬性塊(在文件頭上)的 “SHA1-Digest-Manifest” 屬性值值下。然後,再逐條計算 MANIFEST.MF 文件中每一個塊的 SHA1,並經過 BASE64 編碼後,記錄在 CERT.SF 中的同名塊中,屬性的名字是 “SHA1-Digest” 。

Signature-Version: 1.0
Created-By: 1.0 (Android)
SHA1-Digest-Manifest: MJQyZ0dc4dv7G9nlJPAMQLwEwbU=
X-Android-APK-Signed: 2

Name: AndroidManifest.xml
SHA1-Digest: IJioMmfD693T4qnUJcPKhq9woHQ=

Name: META-INF/android.arch.core_runtime.version
SHA1-Digest: OPQCkzMXJVPQryHeMowVNZmfRMw=

Name: META-INF/android.arch.lifecycle_livedata-core.version
SHA1-Digest: TSBGEIW1zN2n2sraHWcuRYSO8JU=

3、把之前生成的 CERT.SF 文件, 用私鑰計算出簽名, 然後將簽名以及包含公鑰信息的數字證書一同寫入 CERT.RSA 中保存。

3082 02f9 0609 2a86 4886 f70d 0107 02a0
8202 ea30 8202 e602 0101 310b 3009 0605
2b0e 0302 1a05 0030 0b06 092a 8648 86f7
0d01 0701 a082 01e1 3082 01dd 3082 0146
0201 0130 0d06 092a 8648 86f7 0d01 0105
0500 3037 3116 3014 0603 5504 030c 0d41
6e64 726f 6964 2044 6562 7567 3110 300e
0603 5504 0a0c 0741 6e64 726f 6964 310b
3009 0603 5504 0613 0255 5330 1e17 0d31

簽名校驗

1、完整性校驗

如果 APK 中文件被修改,對應 MANIFEST.MF 中的 SHA1 會發生改變。

2、APK 作者身份唯一性校驗

當在 Android 設備上安裝 APK 包時,會從存放在 CERT.RSA 中的公鑰證書中提取公鑰,進行 RSA 解密來校驗安裝包的身份。 使用不同的 key 生成的簽名信息會不同,不同的私鑰對應不同的公鑰,因此最大的區別是簽名證書中存放的公鑰會不同,所以我們可以通過提取 CERT.RSA 中的公鑰來檢查安裝包是否被重新簽名了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章