Android應用程序簽名過程和解析過程

非對稱加密算法

非對稱加密算法需要兩個密鑰:公開密鑰(簡稱公鑰)和私有密鑰(簡稱私鑰)。公鑰與私鑰是一對,如果用公鑰對數據進行加密,只有用對應的私鑰才能解密;如果用私鑰對數據進行加密,那麼只有用對應的公鑰才能解密。因爲加密和解密使用的是兩個不同的密鑰,所以這種算法叫作非對稱加密算法。非對稱加密算法是數字簽名和數字證書的基礎,大家非常熟悉的RSA就是非對稱加密算法的一種實現。

消息摘要算法

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

1)無論輸入的消息有多長,計算出來的消息摘要的長度總是固定的。例如應用MD5算法摘要的消息有128個比特位,用SHA-1算法摘要的消息最終有160比特位的輸出。

2)一般來說(不考慮碰撞的情況下),只要輸入的原始數據不同,對其進行摘要以後產生的消息摘要也必不相同,即使原始數據稍有改變,輸出的消息摘要便完全不同。但是,相同的輸入必會產生相同的輸出。

3)具有不可逆性,即只能進行正向的信息摘要,而無法從摘要中恢復出任何的原始消息。

數字簽名和數字證書

數字簽名和數字證書其實數字簽名的概念很簡單。

大家知道,要確保可靠通信,必須要解決兩個問題:
首先,要確定消息的來源確實是其申明的那個人;
其次,要保證信息在傳遞的過程中不被第三方篡改,即使被篡改了,也可以發覺出來。

所謂數字簽名,就是爲了解決這兩個問題而產生的,它是對前面提到的非對稱加密技術與數字摘要技術的一個具體的應用。對於消息的發送者來說,先要生成一對公私鑰對,將公鑰給消息的接收者。如果消息的發送者有一天想給消息接收者發消息,在發送的信息中,除了要包含原始的消息外,還要加上另外一段消息。

這段消息通過如下兩步生成:
1)對要發送的原始消息提取消息摘要;
2)對提取的信息摘要用自己的私鑰加密。

通過這兩步得出的消息,就是所謂的原始信息的數字簽名。而對於信息的接收者來說,他所收到的信息,將包含兩個部分,一是原始的消息內容,二是附加的那段數字簽名。

他將通過以下三步來驗證消息的真僞:
1)對原始消息部分提取消息摘要,注意這裏使用的消息摘要算法要和發送方使用的一致;
2)對附加上的那段數字簽名,使用預先得到的公鑰解密;
3)比較前兩步所得到的兩段消息是否一致。如果一致,則表明消息確實是期望的發送者發的,且內容沒有被篡改過;相反,如果不一致,則表明傳送的過程中一定出了問題,消息不可信。

通過這種所謂的數字簽名技術,確實可以有效解決可靠通信的問題。如果原始消息在傳送的過程中被篡改了,那麼在消息接收者那裏,對被篡改的消息提取的摘要肯定和原始的不一樣。並且,由於篡改者沒有消息發送方的私鑰,即使他可以重新算出被篡改消息的摘要,也不能僞造出數字簽名。

所以,綜上所述,數字簽名其實就是隻有信息的發送者才能產生的別人無法僞造的一段數字串,這段數字串同時也是對信息的發送者發送信息真實性的一個有效證明。不知道大家有沒有注意,前面講的這種數字簽名方法,有一個前提,就是消息的接收者必須要事先得到正確的公鑰。如果一開始公鑰就被別人篡改了,那壞人就會被你當成好人,而真正的消息發送者給你發的消息會被你視作無效的。而且,很多時候根本就不具備事先溝通公鑰的信息通道。那麼如何保證公鑰的安全可信呢?這就要靠數字證書來解決了。

所謂數字證書,一般包含以下一些內容:
證書的發佈機構(Issuer)證書的有效期(Validity)消息發送方的公鑰證書所有者(Subject)數字簽名所使用的算法數字簽名

可以看出,數字證書其實也用到了數字簽名技術。只不過要簽名的內容是消息發送方的公鑰,以及一些其它信息。但與普通數字簽名不同的是,數字證書中籤名者不是隨隨便便一個普通的機構,而是要有一定公信力的機構。這就好像你的大學畢業證書上簽名的一般都是德高望重的校長一樣。一般來說,這些有公信力機構的根證書已經在設備出廠前預先安裝到了你的設備上了。所以,數字證書可以保證數字證書裏的公鑰確實是這個證書的所有者的,或者證書可以用來確認對方的身份。數字證書主要是用來解決公鑰的安全發放問題。

綜上所述,總結一下,數字簽名和簽名驗證的大體流程如下圖所示:

數字簽名和簽名驗證的大體流程數字簽名和簽名驗證的大體流程

Android應用程序簽名流程

Android採用的是開放的生態系統,任何人都可以開發和發佈應用程序給別人使用。不像iOS,在沒有被破解的情況下只能通過App Store安裝應用,Android在打開了“Unknow Sources”選項後,可以安裝任何來源的應用程序,可以是第三方市場,可以是自己開發的應用,也可以從論壇下載。

那麼問題來了,對於有一些不懷好意的人,完全可以拿到一個原生的應用,然後加入一些惡意的代碼,再發布出去,誘使別人去安裝,達到不可告人的目的。有沒有什麼辦法可以防止應用程序在傳送的過程中被第三方惡意篡改呢?

Google因此引入了應用程序簽名機制。它是如何工作的呢?我們先來看看簽名前後,一個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,敲入以下命令:

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設備上安裝,必須對其進行重簽名。

總結

1)Android應用程序簽名只是用來解決發佈的應用不被別人篡改的,其並不會對應用程序本身進行加密,這點不同於Windows Phone和iOS。
2)Android並不要求所有應用程序的簽名證書都由可信任CA的根證書籤名,通過這點保證了其生態系統的開放性,所有人都可以用自己生成的證書對應用程序簽名。
3)如果想修改一個已經發布的應用程序,哪怕是修改一張圖片,都必須對其進行重新簽名。但是,籤原始應用的私鑰一般是拿不到的(肯定在原始應用程序開發者的手上,且不可能公佈出去),所以只能用另外一組公私鑰對,生成一個新的證書,對重打包的應用進行簽名。所以重打包的apk中所帶證書的公鑰肯定和原始應用不一樣。

同時,在手機上如果想安裝一個應用程序,應用程序安裝器會先檢查相同包名的應用是否已經被安裝過,如果已經安裝過,會繼續判斷已經安裝的應用和將要安裝的應用,其所攜帶的數字證書中的公鑰是否一致。如果相同,則繼續安裝;而如果不同,則會提示用戶先卸載前面已安裝的應用。通過這種方式來提示用戶,前後兩個應用是不同開發者簽名的,可能有一個是李鬼。

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