Android的APK應(yīng)用簽名機制以及讀取簽名的方法
發(fā)布過Android應(yīng)用的朋友們應(yīng)該都知道,Android APK的發(fā)布是需要簽名的。簽名機制在Android應(yīng)用和框架中有著十分重要的作用。例如,Android系統(tǒng)禁止更新安裝簽名不一致的APK;如果應(yīng)用需要使用system權(quán)限,必須保證APK簽名與Framework簽名一致,等等。
什么是簽名
首先我們得知道什么是摘要,摘要是指采用單向Hash函數(shù)對數(shù)據(jù)進行計算生成的固定長度的Hash值,摘要算法有Md5,Sha1等,Md5生成的Hash值是128位的數(shù)字,即16個字節(jié),用十六進制表示是32個字符,Sha1生成的Hash值是160位的數(shù)字,即20個字節(jié),用十六進制表示是40個字符。我們是不能通過摘要推算出用于計算摘要的數(shù)據(jù),如果修改了數(shù)據(jù),那么它的摘要一定會變化(其實這句話并不正確,只是很難正好找到不同的數(shù)據(jù),而他們的摘要值正好相等)。摘要經(jīng)常用于驗證數(shù)據(jù)的完整性,很多下載網(wǎng)站都會列出下載文件的md5值或者sha1值。
摘要和簽名沒有任何關(guān)系,網(wǎng)上常常將摘要和簽名混為一談,這是錯誤的。簽名和數(shù)字簽名是同一個概念,是指信息的發(fā)送者用自己的私鑰對消息摘要加密產(chǎn)生一個字符串,加密算法確保別人無法偽造生成這段字符串,這段數(shù)字串也是對信息的發(fā)送者發(fā)送信息真實性的一個有效證明。其他發(fā)送者用他們的私鑰對同一個消息摘要加密會得到不同的簽名,接收者只有使用發(fā)送者簽名時使用的私鑰對應(yīng)的公鑰解密簽名數(shù)據(jù)才能得到消息摘要,否則得到的不是正確的消息摘要。
數(shù)字簽名是非對稱密鑰加密技術(shù)+數(shù)字摘要技術(shù)的結(jié)合。
數(shù)字簽名技術(shù)是將信息摘要用發(fā)送者的私鑰加密,和原文以及公鑰一起傳送給接收者。接收者只有用發(fā)送者的公鑰才能解密被加密的信息摘要,然后接收者用相同的Hash函數(shù)對收到的原文產(chǎn)生一個信息摘要,與解密的信息摘要做比對。如果相同,則說明收到的信息是完整的,在傳輸過程中沒有被修改;不同則說明信息被修改過,因此數(shù)字簽名能保證信息的完整性。并且由于只有發(fā)送者才有加密摘要的私鑰,所以我們可以確定信息一定是發(fā)送者發(fā)送的。
另外還需要理解一個概念:數(shù)字證書。數(shù)字證書是一個經(jīng)證書授權(quán)中心數(shù)字簽名的包含公鑰及其擁有者信息的文件。數(shù)字證書的格式普遍采用的是X.509V3國際標(biāo)準(zhǔn),一個標(biāo)準(zhǔn)的X.509數(shù)字證書包含以下一些內(nèi)容:證書的版本信息:
1)證書的序列號,每個證書都有一個唯一的證書序列號;
2)證書所使用的簽名算法;
3)證書的發(fā)行機構(gòu)名稱,命名規(guī)則一般采用X.500格式;
4)證書的有效期,通用的證書一般采用UTC時間格式,它的計時范圍為1950-2049;
5)證書所有人的名稱,命名規(guī)則一般采用X.500格式;
6)證書所有人的公開密鑰;
7)證書發(fā)行者對證書的簽名。
CERT.RSA包含了數(shù)字簽名以及開發(fā)者的數(shù)字證書。CERT.RSA里的數(shù)字簽名是指對CERT.SF的摘要采用私鑰加密后的數(shù)據(jù),Android系統(tǒng)安裝apk時會對CERT.SF計算摘要,然后使用CERT.RSA里的公鑰對CERT.RSA里的數(shù)字簽名解密得到一個摘要,比較這兩個摘要便可知道該apk是否有正確的簽名,也就說如果其他人修改了apk并沒有重新簽名是會被檢查出來的。
需注意Android平臺的證書是自簽名的,也就說不需要權(quán)威機構(gòu)簽發(fā),數(shù)字證書的發(fā)行機構(gòu)和所有人是相同的,都是開發(fā)者自己,開發(fā)者生成公私鑰對后不需要提交到權(quán)威機構(gòu)進行校驗。
讀取簽名
某些時候需要獲取某個特定的apk(已安裝或者未安裝)的簽名信息,如程序自檢測,可信賴的第三方檢測(應(yīng)用市場),系統(tǒng)限定安裝
對此,有兩種實現(xiàn)方法
可以使用Java自帶的API(主要用到的為JarFile,JarEntry,Certificate)進行獲取,還有一種方法是使用系統(tǒng)隱藏的API PackageParser,通過反射來使用對應(yīng)的API.
但是由于安卓系統(tǒng)的分裂版本過多,并且不同廠商進行的修改很多,依賴反射隱藏API的方法并不能保證兼容性和通用性,因此推薦使用JAVA自帶API進行獲取:
/** * 從APK中讀取簽名 * @param file * @return * @throws IOException */ private static List<String> getSignaturesFromApk(File file) throws IOException { List<String> signatures=new ArrayList<String>(); JarFile jarFile=new JarFile(file); try { JarEntry je=jarFile.getJarEntry("AndroidManifest.xml"); byte[] readBuffer=new byte[8192]; Certificate[] certs=loadCertificates(jarFile, je, readBuffer); if(certs != null) { for(Certificate c: certs) { String sig=toCharsString(c.getEncoded()); signatures.add(sig); } } } catch(Exception ex) { } return signatures; } /** * 加載簽名 * @param jarFile * @param je * @param readBuffer * @return */ private static Certificate[] loadCertificates(JarFile jarFile, JarEntry je, byte[] readBuffer) { try { InputStream is=jarFile.getInputStream(je); while(is.read(readBuffer, 0, readBuffer.length) != -1) { } is.close(); return je != null ? je.getCertificates() : null; } catch(IOException e) { } return null; } /** * 將簽名轉(zhuǎn)成轉(zhuǎn)成可見字符串 * @param sigBytes * @return */ private static String toCharsString(byte[] sigBytes) { byte[] sig=sigBytes; final int N=sig.length; final int N2=N * 2; char[] text=new char[N2]; for(int j=0; j < N; j++) { byte v=sig[j]; int d=(v >> 4) & 0xf; text[j * 2]=(char)(d >= 10 ? ('a' + d - 10) : ('0' + d)); d=v & 0xf; text[j * 2 + 1]=(char)(d >= 10 ? ('a' + d - 10) : ('0' + d)); } return new String(text); }
相關(guān)文章
Android程序開發(fā)之Listview下拉刷新上拉(滑動分頁)加載更多
這篇文章主要介紹了Android程序開發(fā)之Listview下拉刷新上拉(滑動分頁)加載更多的相關(guān)資料,非常不錯,具有參考借鑒價值,需要的朋友可以參考下2016-07-07Android EditText 監(jiān)聽用戶輸入完成的實例
下面小編就為大家分享一篇Android EditText 監(jiān)聽用戶輸入完成的實例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-02-02Android自定義ViewGroup(側(cè)滑菜單)詳解及簡單實例
這篇文章主要介紹了Android自定義ViewGroup(側(cè)滑菜單)詳解及簡單實例的相關(guān)資料,需要的朋友可以參考下2017-02-02Android 媒體開發(fā)之MediaPlayer狀態(tài)機接口方法實例解析
這篇文章主要介紹了Android 媒體開發(fā)之MediaPlayer狀態(tài)機接口方法實例解析,需要的朋友可以參考下2017-08-08Android開發(fā)使用URLConnection進行網(wǎng)絡(luò)編程詳解
這篇文章主要介紹了Android開發(fā)使用URLConnection進行網(wǎng)絡(luò)編程,結(jié)合實例形式分析了Android URLConnection對象創(chuàng)建、屬性、方法及相關(guān)使用技巧,需要的朋友可以參考下2018-01-01