編輯:關於Android編程
/** Add the SHA1 of every file to the manifest, creating it if necessary. */ private static Manifest addDigestsToManifest(JarFile jar) throws IOException, GeneralSecurityException { Manifest input = jar.getManifest(); Manifest output = new Manifest(); Attributes main = output.getMainAttributes(); if (input != null) { main.putAll(input.getMainAttributes()); } else { main.putValue("Manifest-Version", "1.0"); main.putValue("Created-By", "1.0 (Android SignApk)"); } ...... for (JarEntry entry: byName.values()) { String name = entry.getName(); if (!entry.isDirectory() && !name.equals(JarFile.MANIFEST_NAME) && !name.equals(CERT_SF_NAME) && !name.equals(CERT_RSA_NAME) && (stripPattern == null || !stripPattern.matcher(name).matches())) { InputStream data = jar.getInputStream(entry); while ((num = data.read(buffer)) > 0) { md.update(buffer, 0, num); } Attributes attr = null; if (input != null) attr = input.getAttributes(name); attr = attr != null ? new Attributes(attr) : new Attributes(); attr.putValue("SHA1-Digest", base64.encode(md.digest())); output.getEntries().put(name, attr); } } return output; }遍歷APK包中的每一個文件,利用SHA1算法生成這些文件的摘要信息。 驗證是所有文件使用的SHA1算法: 1.安裝hashTab工具
Name: AndroidManifest.xml SHA1-Digest: Zovq4AVMcCjFkILZLlHgmeOLvnU=其中找到文件中的AndroidManifest.xml文件,查看其對應的hash值,如圖3所示。 這裡取出16進制的668BEAE0054C7028C59082D92E51E099E38BBE75,將16進制通過在線轉碼網站:hex to base64轉化為對應的base64編碼,看見“Zovq4AVMcCjFkILZLlHgmeOLvnU=”與記錄信息相對的。
// CERT.SF Signature signature = Signature.getInstance("SHA1withRSA"); signature.initSign(privateKey); je = new JarEntry(CERT_SF_NAME); je.setTime(timestamp); outputJar.putNextEntry(je); writeSignatureFile(manifest, new SignatureOutputStream(outputJar, signature));
/** Write a .SF file with a digest of the specified manifest. */ private static void writeSignatureFile(Manifest manifest, SignatureOutputStream out) throws IOException, GeneralSecurityException { Manifest sf = new Manifest(); Attributes main = sf.getMainAttributes(); main.putValue("Signature-Version", "1.0"); main.putValue("Created-By", "1.0 (Android SignApk)"); BASE64Encoder base64 = new BASE64Encoder(); MessageDigest md = MessageDigest.getInstance("SHA1"); PrintStream print = new PrintStream( new DigestOutputStream(new ByteArrayOutputStream(), md), true, "UTF-8"); // Digest of the entire manifest manifest.write(print); print.flush(); main.putValue("SHA1-Digest-Manifest", base64.encode(md.digest())); Map雖然writeSignatureFile字面上看起來是寫簽名文件,但是CERT.SF的生成和私鑰沒有一分錢的關系,實際上也不應該有一分錢的關系,這個文件自然不保存任何簽名內容。CERT.SF中保存的是MANIFEST.MF的摘要值(第一項),entries = manifest.getEntries(); for (Map.Entry entry : entries.entrySet()) { // Digest of the manifest stanza for this entry. print.print("Name: " + entry.getKey() + "\r\n"); for (Map.Entry
Signature-Version: 1.0 Created-By: 1.0 (Android) SHA1-Digest-Manifest: nGpBbfOirA4fsY0pn0dBONop5bQ=以及MANIFEST.MF中每一個摘要項的摘要值。我也沒搞清楚為什麼要引入CERT.SF,實際上我也覺得簽名完全可以用MANIFEST.MF生成。
Name: AndroidManifest.xml SHA1-Digest: PJblxooLyYkHHlr/0lKZkk2DkM0=在將MANIFEST.MF條目取出,保存為“新建文本文檔.txt”,查看對應的消息摘要,並將其轉換為base64編碼,如圖5所示。 圖5 新建文本文檔.txt的消息摘要和對應的base64編碼 這裡完成了對CERT.SF的驗證。
// CERT.RSA je = new JarEntry(CERT_RSA_NAME); je.setTime(timestamp); outputJar.putNextEntry(je); writeSignatureBlock(signature, publicKey, outputJar);
/** Write a .RSA file with a digital signature. */ private static void writeSignatureBlock( Signature signature, X509Certificate publicKey, OutputStream out) throws IOException, GeneralSecurityException { SignerInfo signerInfo = new SignerInfo( new X500Name(publicKey.getIssuerX500Principal().getName()), publicKey.getSerialNumber(), AlgorithmId.get("SHA1"), AlgorithmId.get("RSA"), signature.sign()); PKCS7 pkcs7 = new PKCS7( new AlgorithmId[] { AlgorithmId.get("SHA1") }, new ContentInfo(ContentInfo.DATA_OID, null), new X509Certificate[] { publicKey }, new SignerInfo[] { signerInfo }); pkcs7.encodeSignedData(out); }這個文件保存了簽名和公鑰證書。簽名的生成一定會有私鑰參與,簽名用到的信息摘要就是CERT.SF內容。
Certificate: Data: Version: 3 (0x2) Serial Number: 1281971851 (0x4c69568b) Signature Algorithm: sha1WithRSAEncryption Issuer: CN=Michael Liu Validity Not Before: Aug 16 15:17:31 2010 GMT Not After : Aug 10 15:17:31 2035 GMT Subject: CN=Michael Liu Subject Public Key Info: Public Key Algorithm: rsaEncryption RSA Public Key: (1024 bit) Modulus (1024 bit): 00:8d:04:84:a2:1e:c6:56:39:f2:cd:a6:f0:48:a5: f7:5e:71:8f:e1:a8:af:a7:dc:66:92:a2:b9:cf:da: 0f:32:42:ce:83:fe:bc:e1:4f:0a:fd:d9:a8:b3:73: f4:ff:97:15:17:87:d6:d0:3c:da:01:fc:11:40:7d: 04:da:31:cc:cd:da:d0:e7:7b:e3:c1:84:30:9f:21: 93:95:20:48:b1:2d:24:02:d2:b9:3c:87:0d:fa:b8: e1:b1:45:f4:8d:90:0a:3b:9d:d8:8a:9a:96:d1:51: 23:0e:8e:c4:09:68:7d:95:be:c6:42:e9:54:a1:5c: 5d:3f:25:d8:5c:c3:42:73:21 Exponent: 65537 (0x10001) Signature Algorithm: sha1WithRSAEncryption 78:3c:6b:ef:71:70:55:68:28:80:4d:f8:b5:cd:83:a9:01:21: 2a:c1:e4:96:ad:bc:5f:67:0c:cd:c3:34:51:6d:63:90:a9:f9: d5:5e:c7:ef:34:43:86:7d:68:e1:99:87:92:86:34:91:6d:67: 6d:b2:22:e9:5e:28:aa:e8:05:52:04:6e:4e:d4:7f:0f:b0:d6: 28:f5:2b:11:38:d5:15:cb:e3:e4:c9:99:23:c1:84:4f:ce:69: e9:b1:59:7b:8e:30:01:1c:e1:92:ee:0d:54:61:29:f5:8e:9e: 42:72:26:2b:aa:c7:af:d9:c9:d1:85:95:8e:4c:8d:5c:77:c5: ce:4e
參考文章:
1.Android為什麼要為app簽名
2.簽名的方法
3.消息摘要、數字簽名、數字證書
4.signApk項目
5.提取CERT.RSA中的公鑰和簽名信息
Activities提供了一種方便管理的創建、保存、回復的對話框機制,例如onCreateDialog(int),onPrepareDialog(int,Dialog),
系統啟動過程圖: Framework層所有的Service都是運行在SystemServer進程中;SystemServer進程是由Zygote進程創建。 S
接著第一個Android UI手勢密碼設計的基礎上繼續改進,效果圖如下activity_main.xml<LinearLayout xmlns:android=ht
先來看看效果:首先來分析一下:這個菜單可以分成三個菜單:1.一級菜單(即最內圈那個菜單)2.二級菜單(即中間圈那個菜單)3.三級菜單(即最外圈那個菜單)首先,可以將這三個