准備知識:數據摘要
這個知識點很好理解,百度百科即可,其實他也是一種算法,就是對一個數據源進行一個算法之后得到一個摘要,也叫作數據指紋,不同的數據源,數據指紋肯定不一樣,就和人一樣。
消息摘要算法(Message Digest Algorithm)是一種能產生特殊輸出格式的算法,其原理是根據一定的運算規則對原始數據進行某種形式的信息提取,被提取出的信息就被稱作原始數據的消息摘要。
著名的摘要算法有RSA公司的MD5算法和SHA-1算法及其大量的變體。
消息摘要的主要特點有:
1)無論輸入的消息有多長,計算出來的消息摘要的長度總是固定的。例如應用MD5算法摘要的消息有128個比特位,用SHA-1算法摘要的消息最終有160比特位的輸出。
2)一般來說(不考慮碰撞的情況下),只要輸入的原始數據不同,對其進行摘要以后產生的消息摘要也必不相同,即使原始數據稍有改變,輸出的消息摘要便完全不同。但是,相同的輸入必會產生相同的輸出。
3)具有不可逆性,即只能進行正向的信息摘要,而無法從摘要中恢復出任何的原始消息。
一 Android簽名機制及原理
Android系統在安裝APK的時候,首先會檢驗APK的簽名,如果發現簽名文件不存在或者校驗簽名失敗,則會拒絕安裝,所以應用程序在發布之前一定要進行簽名。給APK簽名可以帶來以下好處:
應用程序升級
如果想無縫升級一個應用,Android系統要求應用程序的新版本與老版本具有相同的簽名與包名。若包名相同而簽名不同,系統會拒絕安裝新版應用。
應用程序模塊化
Android系統可以允許同一個證書簽名的多個應用程序在一個進程里運行,系統實際把他們作為一個單個的應用程序。此時就可以把我們的應用程序以模塊的方式進行部署,而用戶可以獨立的升級其中的一個模塊。
代碼或數據共享
Android提供了基於簽名的權限機制,一個應用程序可以為另一個以相同證書簽名的應用程序公開自己的功能與數據,同時其它具有不同簽名的應用程序不可訪問相應的功能與數據。
應用程序的可認定性
簽名信息中包含有開發者信息,在一定程度上可以防止應用被偽造。例如網易雲加密對Android APK加殼保護中使用的“校驗簽名(防二次打包)”功能就是利用了這一點。
簽名原理
對一個APK文件簽名之后,APK文件根目錄下會增加META-INF目錄,該目錄下增加三個文件:
MANIFEST.MF
NETEASE.RSA
NETEASE.SF
其中.RSA文件還可能是.DSA文件,RSA與SF文件的文件名可以更改,但是它們的命名必須一樣。
MANIFEST.MF中保存了APK里所有文件的SHA1校驗值的BASE64編碼,格式如下(一個文件對應一條記錄):
Name: res/anim/abc_fade_in.xml
SHA1-Digest: ohPEA4mboaFUu9LZMUwk7FmjbPI=
Name: res/anim/abc_fade_out.xml
SHA1-Digest: MTJWZc22b5LNeBboqBhxcQh5xHQ=
SF文件里保存了MANIFEST.MF文件的SHA1校驗值的BASE64編碼,同時還保存了MANIFEST.MF中每一條記錄的SHA1檢驗值BASE64編碼,格式如下:
SHA1-Digest-Manifest: ZRhh1HuaoEKMn6o21W1as0sMlaU=
Name: res/anim/abc_fade_in.xml
SHA1-Digest: wE1QEZhFkLBWMw4TRtxPdsiMRtA=
Name: res/anim/abc_fade_out.xml
SHA1-Digest: MfCV1efdxSKtesRMF81I08Zyvvo=
RSA文件則包含了簽名的公鑰、簽名所有者等信息,還保存了http://my.oschina.net/u/816213/blog/685762?fromerr=RSS3IhKo用SHA1withRSA簽名算法對SF文件的簽名結果信息。
Android系統就是根據這三個文件的內容對APK文件進行簽名檢驗的。
二 Android 簽名方法
1、apksign、jarsinger
一般的簽名過程可以由apksign.jar或者jarsinger.jar完成。apksign.jar由Android SDK提供,使用方法如下:
java -jar signapk.jar testkey.x509.pem testkey.pk8 update.apk update_signed.apk
它接受一個PEM公鑰文件,PK8私鑰文件,對update.apk進行簽名,簽名后的文件保存到update_signed.apk。
jarsinger是由JDK提供,使用方法如下:
jarsigner -verbose -keystore d:\\debug.keystore -signedjar update_signed.apk update.apk androiddebugkey -digestalg SHA1 -sigalg MD5withRSA -keypass android -storepass android
其中:
-keystore表示keystore文件的路徑
androiddebugkey 表示keystore中的一個別名
-digestalg表示摘要算法
-sigalg 表示簽名算法
-keypass 表示別名密碼
-storepass表示keystore密碼
經過測試,發現以上兩個傳統的簽名工具存在以下缺點:
1)、jarsigner在對一個已經有META-INF目錄的APK進行簽名的時候,有可能會報錯:
jarsigner: 無法對 jar 進行簽名: java.util.zip.ZipException: invalid entry compressed size (expected 1368 but got 1379 bytes)
2)、如果APK中已經有簽名文件且簽名文件中的RSA(或DSA)、SF文件的命名不是CERT的時候,用這兩個簽名工具進行簽名后,會出現:
META-INF目錄下會有兩個RSA/SF文件,會導致APK在安裝的時候失敗。
3)、簽名花費時間長。這兩個簽名工具在生成簽名后的APK時,是按Zip中一個entry接一個entry 依次拷貝的,效率十分低。因為游戲類型APK類文件數量一般比較多,所以這一缺陷在簽名游戲類型APK時,體現得尤為明顯。
2、極速簽名工具(ApkSinger)
極速簽名工具克服了signapk.jar與jarsigner在簽名過程的缺點,使用方法:
java -jar ApkSigner.jar [-appname test] -keystore keystorePath -alias alias [-pswd password] [-aliaspswd aliasPassword] apkPath(or directory)
-appname 待簽名的應用程序名,可選,但建議不同的APP填上對應的app名
-keystore 后跟.keystore簽名文件
-alias 后跟簽名別名
-pswd 后跟對應簽名的密碼,可選,如果不填,則簽名的時候需要手動輸入
-aliaspswd 對應別名alias的密碼,如果沒有則默認使用keystore Password
最后跟待簽名的APK路徑或者目錄路徑 ,如果跟的是目錄則是批量簽名.
三、為何要這么來簽名
上面我們就介紹了簽名apk之后的三個文件的詳細內容,那么下面來總結一下,Android中為何要用這種方式進行加密簽名,這種方加密是不是最安全的呢?下面我們來分析一下,如果apk文件被篡改后會發生什么。
首先,如果你改變了apk包中的任何文件,那么在apk安裝校驗時,改變后的文件摘要信息與MANIFEST.MF的檢驗信息不同,於是驗證失敗,程序就不能成功安裝。
其次,如果你對更改的過的文件相應的算出新的摘要值,然后更改MANIFEST.MF文件里面對應的屬性值,那么必定與CERT.SF文件中算出的摘要值不一樣,照樣驗證失敗。
最后,如果你還不死心,繼續計算MANIFEST.MF的摘要值,相應的更改CERT.SF里面的值,那么數字簽名值必定與CERT.RSA文件中記錄的不一樣,還是失敗。
那么能不能繼續偽造數字簽名呢?不可能,因為沒有數字證書對應的私鑰。
所以,如果要重新打包后的應用程序能再Android設備上安裝,必須對其進行重簽名。
從上面的分析可以得出,只要修改了Apk中的任何內容,就必須重新簽名,不然會提示安裝失敗,當然這里不會分析,后面一篇文章會注重分析為何會提示安裝失敗。