Android開發(fā)簽名知識(shí)梳理總結(jié)
前言
最近幫測(cè)試做了一點(diǎn)關(guān)于簽名的需求,今天就和各位同學(xué)簡(jiǎn)單聊一聊關(guān)于簽名的那些事兒。
如果問(wèn)到 Android 為什么需要簽名?大家都可能想到官網(wǎng)的解釋:
Android 系統(tǒng)要求所有 APK 必須先使用證書進(jìn)行數(shù)字簽名,然后才能安裝到設(shè)備上進(jìn)行更新。
這是一個(gè)比較模糊的解釋,簡(jiǎn)單來(lái)說(shuō),有了簽名,就可以讓 App 和開發(fā)者綁定。
畢竟,應(yīng)用那么多,別的開發(fā)者也有可能盜用你的代碼,這個(gè)時(shí)候,包名和你相同,代碼和你相同,怎么區(qū)分你的 App 和這些人的 App 不是同一個(gè)呢?
這個(gè)時(shí)候數(shù)字簽名就派上用場(chǎng)了。
一、簽名基礎(chǔ)
想要徹底了解簽名知識(shí),我們得了解以下知識(shí):
- 消息摘要
- 數(shù)字簽名
- 加密
- 數(shù)字證書
這一系列的知識(shí)各位可能在學(xué)習(xí)網(wǎng)絡(luò)的時(shí)候或多或少的接觸過(guò)。
我們簡(jiǎn)單的學(xué)習(xí)一下這些知識(shí):
1. 消息摘要
消息摘要常常被被稱為數(shù)字摘要或者數(shù)字指紋,定義如下:
在原來(lái)的數(shù)據(jù)基礎(chǔ)上,經(jīng)過(guò)一個(gè)單向的 Hash 計(jì)算,得到一個(gè)固定的 Hash 值,這就是消息摘要。
常見的摘要算法都有 MD5、SHA-1 和 SHA-256,特點(diǎn)如下:
- 長(zhǎng)度固定,與內(nèi)容長(zhǎng)度無(wú)關(guān):比如 MD5 是 128 位、SHA-1 是 160 位、SHA-256 是 256 位。
- 看似隨機(jī),其實(shí)不隨機(jī):同內(nèi)容兩次摘要得出的結(jié)果一致
- 單向:只能從原數(shù)據(jù)得出摘要,不能從消息摘要得出原來(lái)的數(shù)據(jù)
- 優(yōu)秀的摘要算法很難 Hash 碰撞
基于此,消息摘要常常會(huì)被用來(lái)檢查內(nèi)容的完整性。
比如我們下載起點(diǎn)讀書,消息摘要的用法如下:
- 計(jì)算摘要:App 會(huì)針對(duì)自己的文件信息計(jì)算出一個(gè)數(shù)字摘要比如
123**...**123 - 下載App
- 驗(yàn)證摘要:對(duì)下載的 App 再次計(jì)算摘要,比如得出的也是
123**...**123,和之前的數(shù)字摘要一對(duì)比,這就代表我從服務(wù)器下載的內(nèi)容是完整的,可以正常使用
當(dāng)然,上面值涉及了摘要部分,其他過(guò)程,我們后面分析。
2. 加密算法
什么是加密?
百科是這么解釋的:
將明文信息改變?yōu)殡y以讀取的密文內(nèi)容,使之不可讀的過(guò)程。只有擁有解密方法的對(duì)象,經(jīng)由解密過(guò)程,才能將密文還原為正常可讀的內(nèi)容。
所以啊,加密方法得到的密文是可以轉(zhuǎn)變?yōu)槊魑牡?,像信息摘要算法比?MD5 得出來(lái)的結(jié)果是不可逆的,所以面試官問(wèn)你們什么事加密算法的時(shí)候,你可不能把 MD5 說(shuō)進(jìn)去!
加密算法分為兩大類,對(duì)稱加密和非對(duì)稱加密。
2.1 對(duì)稱加密
對(duì)稱加密在加密和解密的時(shí)候使用的同一把鑰匙:

2.2 非對(duì)稱加密
非對(duì)稱加密是使用公鑰/私鑰中的公鑰來(lái)加密明文,然后使用對(duì)應(yīng)的私鑰來(lái)解密密文的過(guò)程:

簡(jiǎn)單對(duì)比一下對(duì)稱加密和非對(duì)稱機(jī)密:
| 非對(duì)稱加密 | 對(duì)稱加密 | |
|---|---|---|
| 速度 | 慢 | 快 |
| 效率 | 低 | 高 |
| 安全性 | 高 | 低 |
| 常見算法 | RSA\DH | AES\DES\IDEA |
2.3 使用場(chǎng)景
學(xué)過(guò)網(wǎng)絡(luò)的同學(xué)應(yīng)該都了解,在 Https 的傳輸過(guò)程中,客戶端和服務(wù)端使用非對(duì)稱加密生成對(duì)稱加密的密鑰,然后用對(duì)稱加密傳輸網(wǎng)絡(luò)中的數(shù)據(jù)。
比如我上大學(xué)那會(huì)兒,每個(gè)月的月尾我和我媽的對(duì)話是這樣的:

網(wǎng)絡(luò)環(huán)境是開放的,萬(wàn)一這時(shí),有一個(gè)黑客監(jiān)聽了我和我媽的對(duì)話,過(guò)程就變成了這樣:

在我發(fā)卡號(hào)的時(shí)候,黑客將我的卡號(hào)改成了它的卡號(hào),于是我的生活費(fèi)變成了他的生活費(fèi)。
為了避免這種情況,于是我和我媽約定好了,每次發(fā)送前,使用對(duì)稱加密對(duì)消息進(jìn)行加密,接受消息的時(shí)候使用密鑰解密,過(guò)程就變成了這樣:

中間人再也不能獲取到消息了,看似一點(diǎn)問(wèn)題都沒(méi)有,但是我和老媽之間如何確定密鑰呢?
密鑰總要在互聯(lián)網(wǎng)之間進(jìn)行傳輸?shù)?,有傳輸就有被中間人截獲的風(fēng)險(xiǎn),一旦被截獲,錢可就沒(méi)了!
為了解決對(duì)稱加密鑰匙傳輸?shù)膯?wèn)題,我和老媽用上了非對(duì)稱加密,像這樣:

即使這樣,還是有問(wèn)題存在:
- 怎么才能確認(rèn)我獲得的公鑰來(lái)自老媽?
- 如何確定消息確實(shí)來(lái)自老媽?
解決這兩個(gè)問(wèn)題也很簡(jiǎn)單,一是數(shù)字簽名,二就是數(shù)字證書。
3. 數(shù)字簽名
數(shù)字簽名的作用是為了消息的完整性。
在非對(duì)稱加密的體系下,消息的發(fā)送過(guò)程是這樣的,還是上面的例子:

數(shù)字簽名的過(guò)程是這樣的:
- 我發(fā)送消息前,利用 Hash 算法針對(duì)數(shù)據(jù)得出一個(gè)摘要
- 我使用老媽的公鑰對(duì)摘要內(nèi)容進(jìn)行加密,連同對(duì)稱加密的數(shù)據(jù)一起發(fā)送過(guò)去
- 老媽接收到消息后,先利用對(duì)稱密鑰對(duì)內(nèi)容解密,再進(jìn)行 Hash 計(jì)算得出摘要
- 老媽使用私鑰將摘要內(nèi)容解密,和再次計(jì)算得出的摘要作對(duì)比,一致就代表消息無(wú)誤
上面的這種場(chǎng)景其實(shí)有點(diǎn)不妥,數(shù)字簽名一般用在證書上,協(xié)商好對(duì)稱密鑰以后一般不會(huì)進(jìn)行消息完整性校驗(yàn)了,不過(guò)大伙只要了解數(shù)字簽名要來(lái)校驗(yàn)消息完整性就好。
截止現(xiàn)在,還有最后一個(gè)問(wèn)題,我無(wú)法確認(rèn)獲取的公鑰確實(shí)來(lái)自老媽。
4. 數(shù)字證書
證書的作用很簡(jiǎn)單,證明公鑰的身份。
就像在現(xiàn)實(shí)中,大家都是怎么證明自己的身份的?
沒(méi)錯(cuò),是身份證。你有沒(méi)有發(fā)現(xiàn),每張身份證,會(huì)有三種信息:
- 自身的信息
- 置辦身份證的派出所
- 有效期
對(duì)應(yīng)的數(shù)字證書也有很多內(nèi)容:
- CA:證書的頒發(fā)機(jī)構(gòu)
- 證書的有效期
- 公鑰
- 證書的授予對(duì)象
CA 將這些內(nèi)容利用 CA 的私鑰進(jìn)行簽名,用戶使用 CA 的公鑰驗(yàn)簽,從而證明公鑰的身份。
常見的證書分為兩種:
- 簽名證書:由 CA 機(jī)構(gòu)頒發(fā),絕大部分網(wǎng)站都采用的這種方式
- 自簽名證書:由服務(wù)器自己頒發(fā)給自己
重回之前的例子,老媽只需要將自己的簽名證書發(fā)給我,我就可以獲取她的公鑰,之后就可以正常的通信。
二、Android簽名機(jī)制
在 Android 中,也需要使用數(shù)字證書做數(shù)字簽名,數(shù)字證書中公鑰對(duì)應(yīng)的私鑰由開發(fā)者持有。
在 Android Studio 中,最終會(huì)生成一個(gè) .jks 的文件,早期 Eclipse 是 .keystore,它們都是用作證書和私鑰的二進(jìn)制文件。
App 如果使用了一種私鑰簽名,另外一個(gè)私鑰簽名的文件將無(wú)法安裝或覆蓋老的版本,這樣做是為了防止已經(jīng)安裝的 App 被惡意的第三方覆蓋。
1. Android簽名機(jī)制的異同點(diǎn)
Android 中數(shù)字簽名的生成和普通的數(shù)字簽名并沒(méi)有很大的區(qū)別。
但是進(jìn)行數(shù)字簽名的證書可以采用自簽名證書,即不需要權(quán)威證書頒發(fā)機(jī)構(gòu)(CA)來(lái)做背書,因?yàn)樗淖饔檬怯脕?lái)標(biāo)識(shí)應(yīng)用程序的開發(fā)者,下載的用戶并不需要這個(gè)證書來(lái)下載該 App。
2. Debug和Relase的簽名
當(dāng)我們?cè)贗DE中運(yùn)行或調(diào)試項(xiàng)目時(shí),AS 會(huì)自動(dòng)使用 Android SDK 工具生成的調(diào)試證書為我們的應(yīng)用簽名,路徑為 $HOME/.android/debug.keystore,但是應(yīng)用商店可不接受使用調(diào)試證書發(fā)布的應(yīng)用簽名。
打包Release時(shí),我們一般會(huì)在 app 模塊中的 build.gradle 進(jìn)行配置:
android {
? ...
? signingConfigs {
? ? ? release {
? ? ? ? ? storeFile file("release.keystore")
? ? ? ? ? storePassword "******"
? ? ? ? ? keyAlias "******"
? ? ? ? ? keyPassword "******"
? ? ? }
? }
}
這些都是我們生成 .jks 或者 .keystore 需要生成的參數(shù)。
三、簽名方案
目前 Android 支持以下四種應(yīng)用簽名方案:
- v1方案:基于 JAR 簽名
- v2方案:Android 7.0 引入,改動(dòng)大
- v3方案:Android 9.0 引入,基于 v2 的升級(jí)
- v4方案:Android 11.0 引入,用來(lái)支持 ADB 增量 APK 安裝
1 v1方案
v1 是一個(gè)老生常談的簽名了,簽名過(guò)程也很簡(jiǎn)單。
我們?nèi)绻x中一個(gè)任意簽名后的 apk 進(jìn)行解壓,會(huì)找到一個(gè) META-INF 文件,這個(gè)文件里一般會(huì)有以 MF、SF 和 RSA 結(jié)尾的文件,如圖:

這些文件在 v1 簽名流程中是這樣的:

驗(yàn)證過(guò)程在 Apk 安裝的過(guò)程中:

整個(gè)過(guò)程清晰明了,但 v1 有兩個(gè)問(wèn)題:
第一個(gè)問(wèn)題是簽名校驗(yàn)慢,要針對(duì) Apk 中所有的文件進(jìn)行校驗(yàn),這會(huì)拖累老設(shè)備的安裝時(shí)間。
第二個(gè)問(wèn)題是僅針對(duì) ZIP 條目校驗(yàn),META-INF 文件不會(huì)計(jì)入校驗(yàn)過(guò)程。這樣會(huì)導(dǎo)致即使我 Apk 已經(jīng)簽過(guò)名,工程師也可以移動(dòng)條目順序并重新壓縮,也可以修改 META-INF 文件下的內(nèi)容,帶來(lái)一些安全隱患,早期的多渠道打包就是在這里做的文章。
2. v2方案
v2 是 Android 簽名方案的一大步,它解決了 v1 遺留的簽名校驗(yàn)慢和完整性的問(wèn)題。
我們先來(lái)看一下 v2 的組成部分:

v1 的組成部分其實(shí)就和 Before signing 那一塊兒一樣,v2 多了紅色區(qū)域,我們稱之為APK簽名分塊。

從保護(hù)的內(nèi)容來(lái)看,v1 僅保護(hù)內(nèi)容1,v2 保護(hù)的區(qū)域有 1、3、4 和 2 的 signed data 區(qū)域,signed data 是 1、3 和 4 得出來(lái)的摘要等信息。
四、簽名過(guò)程
就一個(gè) App 而言,它可能有一個(gè)或者多個(gè)簽名者,對(duì)于每個(gè)簽名者而言,都會(huì)進(jìn)行簽名過(guò)程。
v2 沒(méi)有對(duì)每個(gè)文件都進(jìn)行計(jì)算,而是針對(duì)的所有字節(jié)。它將 1、3 和 4 區(qū)域都拆分成了大小為 1MB 的連續(xù)塊,
計(jì)算方式如下:
- 每個(gè)小塊都按:字節(jié)
0xa5+ 塊字節(jié)長(zhǎng)度 + 塊內(nèi)容 進(jìn)行計(jì)算 - 每個(gè)1、3 和 4 塊都按:字節(jié)
0xa5+ 塊數(shù) + 小塊摘要 進(jìn)行計(jì)算
最后,將這些一個(gè)或者多個(gè)簽名者的摘要、證書等信息都打包到 Apk 中。

驗(yàn)簽過(guò)程:
v2 方案的 APK 驗(yàn)證過(guò)程是這樣的:
- 找到APK簽名分塊區(qū)域
- 每找到一個(gè)簽名者,都會(huì)驗(yàn)證:簽名算法、信息摘要、證書和公鑰
- 所有的簽名者都驗(yàn)證通過(guò)了,APK 驗(yàn)證才會(huì)通過(guò)
1. v3方案
v3 方案建立在 v2 的基礎(chǔ)上,目標(biāo)是解決在更新過(guò)程中更改簽名密鑰的問(wèn)題。
所以 APK 簽名分塊中 添加了兩部分內(nèi)容:
- Proof-of-rotation: 一個(gè)存在替換的所有舊簽名證書的鏈表,根節(jié)點(diǎn)是最舊的證書
- SDK 版本支持
v3 和 v2 的簽名過(guò)程和驗(yàn)證過(guò)程幾乎一致,就不寫出來(lái)了。
2. v4方案
如果同學(xué)們經(jīng)常玩一些主機(jī)游戲,可以發(fā)現(xiàn),在 PS5 或者 Swtich 上,一些游戲即使沒(méi)有安裝完成,我們也可以打開游戲玩一些基本功能,比如我以前常玩的 NBA 2k 系列。
Android 11 中谷歌也新增了 ADB增量APK安裝 功能,比如一個(gè) APK 有 2GB,我下載完 50 MB 以后,就可以使用一些基本功能,剩余的文件通過(guò)后臺(tái)流式傳輸,不過(guò) Android 11 中的這個(gè)功能是面向 ADB 的。
雖然這個(gè)功能很贊,但是對(duì)簽名方案帶來(lái)了一些挑戰(zhàn),之前的方案都是基于所有文件進(jìn)行校驗(yàn)的,于是推出 Android 第四代簽名方案 v4。
v4 基于 APK 所有的字節(jié)計(jì)算出 Merkle Hash 樹,并將 Merkle 樹的根 Hash、鹽值作為簽名數(shù)據(jù)進(jìn)行包完整性校驗(yàn),v4 簽名必須單獨(dú)存在 .idsig 文件中,不會(huì)存在于 APK 文件中,所以 apk 文件中仍然需要 v2 或者 v3 簽名。
3. 向下兼容的簽名方案
Android 中的簽名方案是自上而下兼容的,如圖:

對(duì)于 Android 11 來(lái)說(shuō),驗(yàn)證過(guò)程是這樣的:
- 是否支持 v4,v4 驗(yàn)證完了再驗(yàn)證 v3 或者 v2
- v4 不通過(guò),驗(yàn)證 v3
- v3 不通過(guò),驗(yàn)證 v2
- v2 不通過(guò),驗(yàn)證 v1
- v1 不通過(guò),安裝失敗
對(duì)于 Android 9 來(lái)說(shuō),就得從 v3 方案開始驗(yàn)證的。
到此這篇關(guān)于Android開發(fā)簽名知識(shí)梳理總結(jié)的文章就介紹到這了,更多相關(guān)Android開發(fā)簽名內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Android studio導(dǎo)出APP測(cè)試包和構(gòu)建正式簽名包
- Android Studio簽名打包的兩種方式(圖文教程)
- Android實(shí)現(xiàn)簽名涂鴉手寫板
- Android 自定義View手寫簽名并保存圖片功能
- Android studio設(shè)置指定的簽名文件教程
- Android 項(xiàng)目正式簽名打包教程分享
- Android系統(tǒng)制作自定義簽名的例子
- 使用Android Studio實(shí)現(xiàn)為系統(tǒng)級(jí)的app簽名
- Android 運(yùn)用@JvmName解決函數(shù)簽名沖突問(wèn)題詳解
相關(guān)文章
Android 帶箭頭的指引tipLayout實(shí)現(xiàn)示例代碼
本篇文章主要介紹了Android 帶箭頭的指引tipLayout實(shí)現(xiàn)示例代碼,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-01-01
Android創(chuàng)建與解析XML(二)——詳解Dom方式
本篇文章主要介紹了Android創(chuàng)建與解析XML(二)——詳解Dom方式 ,這里整理了詳細(xì)的代碼,有需要的小伙伴可以參考下。2016-11-11
Android 自定義一套 Dialog通用提示框 (代碼庫(kù))
這篇文章主要介紹了Android 自定義一套 Dialog通用提示框 (代碼庫(kù)),需要的朋友可以參考下2017-04-04
Kotlin FrameLayout與ViewPager2控件實(shí)現(xiàn)滾動(dòng)廣告欄方法
這篇文章主要介紹了Kotlin FrameLayout與ViewPager2控件實(shí)現(xiàn)滾動(dòng)廣告欄,F(xiàn)rameLayout與ViewPager2是Android開發(fā)中非常常見的布局組件,并且它不單單是一個(gè)幀布局組件,可以用它實(shí)現(xiàn)多種功能,感興趣的朋友一起來(lái)看看吧2022-12-12
Android Studio 3.0被調(diào)方法參數(shù)名提示的取消方法
這篇文章主要介紹了去掉android studio 3.0被調(diào)方法參數(shù)名提示的解決方法,在文章末尾給大家補(bǔ)充介紹了Android Studio 3.0 gradle提示太老的解決方法,非常不錯(cuò),需要的朋友可以參考下2017-11-11
Android studio點(diǎn)擊跳轉(zhuǎn)WebView詳解
這篇文章主要為大家詳細(xì)介紹了Android studio點(diǎn)擊跳轉(zhuǎn)WebView的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-09-09
Android?APN數(shù)據(jù)庫(kù)查詢對(duì)比分析(APN案例)
文章詳細(xì)介紹了Android中APN數(shù)據(jù)查詢的實(shí)現(xiàn)方式,文章說(shuō)明了如何避免在主線程進(jìn)行IO操作,從而提高應(yīng)用的響應(yīng)性和用戶體驗(yàn),感興趣的朋友一起看看吧2025-03-03
Android中RecyclerView實(shí)現(xiàn)滑動(dòng)刪除與拖拽功能
這篇文章主要使用了RecyclerView的ItemTouchHelper類實(shí)現(xiàn)了Item的拖動(dòng)和刪除功能,ItemTouchHelper是v7包下的一個(gè)類,下面來(lái)看看詳細(xì)的介紹吧,需要的朋友可以參考學(xué)習(xí)。2017-02-02

