Android中的簽名和簽名文件的生成過程

一、概述

這個玩意簡單說起來很簡單,詳細描述起來很復(fù)雜,復(fù)雜在什么地方呢,首先有一塊陌生的知識點,包括但不限于證書,數(shù)字簽名,加密,密鑰,keytool,keystore,md5,sha1,sha256,base64編碼,文件hash等等。這些東西不是屬于哪門語言,或者屬于哪個平臺。

二、還是從Key Store和keytool說起吧

我們在發(fā)布一款app的時候,肯定要對這款app進行簽名,那么如何生成一個簽過名的apk呢?現(xiàn)在AndroidStudio越來越強大了,直接選擇 Build–>Generate Singed APK 然后選擇next 就可以。

在選擇的過程中,他會讓你選擇Key Store Path 。那么問題來了這個keystore什么東西呢?如果硬要翻譯的話,叫做key(密鑰)store(倉庫)。顧名思義里面的存放的是密鑰,這個密鑰呢分為公鑰和私鑰。如果要類比的話,我感覺類似于sqlite文件的一張表,里面存放了格式化的數(shù)據(jù)。每一條都是一個公私鑰對和一些相關(guān)信息??梢杂泻芏鄺l。

要想弄明白一個東西是啥,是如何運行的,最好的辦法就是弄一個出來觀察一下,為了便于觀察,我借助AndroidStudio來創(chuàng)建這個文件:?

一開始的時候,我們假設(shè)沒有這個keystore,然后我們選中Create New…

為keystore文件選擇一個存儲位置,我放到了桌面上

給這個文件添加打開密碼(類似于壓縮文件的加密),這里我設(shè)置的密碼都是123456

在 keystore 中添加一個條目,這個條目命名為 my_key_1 ,當(dāng)然名字隨便取,這個條目里面存放的是,公私鑰對,和下面6中的一些證書的基本信息。

在 keystore 中的每個條目都有自己單獨的密碼保護。

證書有效期

證書輸入一些關(guān)于您自己的信息。此信息不會顯示在應(yīng)用中,但會作為 APK 的一部分包含在您的證書中。

點擊確定之后,這個條目(key)就被保存到keystore中了。當(dāng)然這keystore里面可以創(chuàng)建多個條目(key)。

keytool是jdk提供的一個把鑰匙和證書儲存到keystore中的工具。而默認的keystore就是一個文件,它用一個密碼保護,要想通過keytool命令打開keystore文件,必須輸入密碼。所有的keystore中條目入口(鑰匙和信任書入口)是通過唯一的別名,并且也需要密碼保護。別名是不區(qū)分大小寫的。通過keytool可以很方便的操作keystore 文件。一篇文章

下面列幾個常用的命令,首先進入到存放keystore 文件的目錄下。下面my_key.keystore是文件名。?

1. 查看證書?

$ keytool -list -v -keystore my_key.keystore -storepass 123456?

2. 從 keystore 導(dǎo)出證書?

$ keytool -export -alias my_key_1 -file my_new.crt -keystore my_key.keystore?

其中 my_key_1 是別名,my_new.crt 是要導(dǎo)出的到的文件的名字,my_key.keystore是 keystore 的路徑

三、數(shù)字簽名和數(shù)字證書

公鑰和私鑰的兩種作用:公共鑰匙用來加密數(shù)據(jù),私有鑰匙用來計算簽名;公鑰加密的消息只能用私鑰解密,私鑰簽名的消息只能用公鑰檢驗簽名。

數(shù)據(jù)摘要:主要有MD5,SHA-1等,用直白的話來說就是通過算法,對輸入的消息(一般是一些二進制數(shù)據(jù))運算后得到一個固定長度的輸出,一般來說輸入不同,得到的摘要也是不同的,并且沒有辦法通過摘要還原數(shù)據(jù)。(其實這也很好理解,顧名思義,好比我們語文中對一篇文章做摘要,不同的文章做的一般不同,而且沒法通過摘要得到整篇文章的原文)?

數(shù)字簽名: 數(shù)字簽名是非對稱密鑰加密技術(shù)數(shù)字摘要技術(shù)的應(yīng)用。(一句話總結(jié)一下就是,私鑰加密后的消息摘要就是數(shù)字簽名)?

數(shù)字簽名一種應(yīng)用場景?:“發(fā)送報文時,發(fā)送方用一個哈希函數(shù)從報文文本中生成報文摘要,然后用自己的私人密鑰對這個摘要進行加密,這個加密后的摘要將作為報文的數(shù)字簽名和報文一起發(fā)送給接收方,接收方首先用與發(fā)送方一樣的哈希函數(shù)從接收到的原始報文中計算出報文摘要,接著再用發(fā)送方的公用密鑰來對報文附加的數(shù)字簽名進行解密,如果這兩個摘要相同、那么接收方就能確認該數(shù)字簽名是發(fā)送方的。

數(shù)字簽名有兩種功效:一是能確定消息確實是由發(fā)送方簽名并發(fā)出來的,因為別人假冒不了發(fā)送方的簽名。二是數(shù)字簽名能確定消息的完整性。因為數(shù)字簽名的特點是它代表了文件的特征,文件如果發(fā)生改變,數(shù)字摘要的值也將發(fā)生變化。不同的文件將得到不同的數(shù)字摘要。 一次數(shù)字簽名涉及到一個哈希函數(shù)、發(fā)送者的公鑰、發(fā)送者的私鑰?!?/p>

但是在【數(shù)字簽名一種應(yīng)用場景】里嗎描述的有個問題,就是前提是接收消息的一方,拿到的公鑰必須是正確的。如果公鑰都被篡改了,那么后面的一切都錯了。數(shù)字證書可以保證數(shù)字證書里面的公鑰確實是這個證書所有者的,這樣就可以解決公鑰的安全發(fā)放了。那么這個證書是哪里來的呢。這就用到了一種約定。我們理論上認為某些有公信力的機構(gòu)發(fā)放的證書是安全的。我們把這些發(fā)放證書的機構(gòu)叫做CA(Certificate Authority)。CA用自己的私鑰對申請證書的人的公鑰和一些基本信息,做簽名,然后把申請者的公鑰,基本信息,和數(shù)字簽名放到一起組成一個證書。而CA本身也會生成一個證書,是自簽名的,也叫根證書,會內(nèi)置在操作系統(tǒng)里面。

四、apk的簽名過程

先看一下一個可安裝的apk包是怎么搞出來的?

從上圖可以看到,簽名發(fā)生在打包過程中的倒數(shù)第二步,而且簽名針對的是已經(jīng)存在的apk包,并不會影響我們寫的代碼。事實也確實是如此,Android的簽名,大致的簽名原理就是對未簽名的apk里面的所有文件計算hash,然后保存起來(MANIFEST.MF),然后在對這些hash計算hash保存起來(CERT.SF),然后在計算hash,然后再通過我們上面生成的keystore里面的私鑰進行加密并保存(CERT.RSA)。很抽象是吧,我們對照著打包好的apk,來看一下

其實對我來說,最常用到簽名的時候,并不是在開發(fā)一個app的時候,而是在逆向一個app的時候,因為Android系統(tǒng)不允許安裝未簽名的apk,所以我們反編譯了別人的apk,想要安裝的話,必須重新簽名。Android反編譯后重新打包apk?

來創(chuàng)建一個測試用的as工程,全部用默認的就行。只不過要修改gradle文件如下:

apply plugin:'com.android.application'android {? ? signingConfigs {? ? ? ? config {? ? ? ? ? ? keyAlias'my_key_1'keyPassword'123456'storeFilefile('/Users/liuqiang/Desktop/my_key.keystore')? ? ? ? ? ? storePassword'123456'}? ? }? ? compileSdkVersion26defaultConfig {? ? ? ? applicationId"me.febsky.myapplication"minSdkVersion19targetSdkVersion26versionCode1versionName"1.0"testInstrumentationRunner"android.support.test.runner.AndroidJUnitRunner"}? ? buildTypes {? ? ? ? release {? ? ? ? ? ? minifyEnabledfalseproguardFiles getDefaultProguardFile('proguard-android.txt'),'proguard-rules.pro' //簽名配置,如果把下面注釋掉,打出的包是未簽名的,如果放開注釋那么是簽名的包 //signingConfig signingConfigs.config}? ? }? ? productFlavors {? ? }}//不關(guān)心依賴

我們可以先生成一個未簽名的apk,然后在生成一個簽名的apk。?

1. 如何生成未簽名的apk?

在app/build.gradle 里面把添加簽名的配置注釋掉:

buildTypes {? ? ? ? release {? ? ? ? ? ? minifyEnabledfalseproguardFiles getDefaultProguardFile('proguard-android.txt'),'proguard-rules.pro'//簽名配置//signingConfig signingConfigs.config}? ? }

然后進入當(dāng)前項目目錄下面運行(aR 是簡寫,assembleRelease ):

$ ./gradlew aR

然后未簽名的apk會存放在 MyApplication/app/build/outputs/apk/release/app-release-unsigned.apk 里面。

如何生成未簽名的apk?

就是把?signingConfig?那行注釋放開就行了其余的一樣,然后未簽名的apk會存放在 MyApplication/app/build/outputs/apk/release/app-release.apk 里面。

簽名apk和未簽名的apk的差別在哪

看文件大小,差不多的大。我們用解壓軟件打開看一下發(fā)現(xiàn)簽名后的/META-INF文件夾里面多了兩個文件,而且MANIFEST.MF 的大小和內(nèi)容是不同的 如下圖:?

如何給未簽名的apk 簽名 命令行運行

$ jarsigner-verbose-keystoremy_key.keystore-signedjarresult_singed.apk app-release-unsigned.apk my_key_1

my_key.keystore keystore文件的路徑

app-release-unsigned.apk 輸入的未簽名文件路徑

my_key_1 keystore里面的一個alias

注:?

jarsigner 是JDK提供的針對jar包簽名的通用工具,?

位于JDK/bin/jarsigner.exe?

apksigner 是Google官方提供的針對Android apk簽名及驗證的專用工具,?

位于Android SDK/build-tools/sdk版本/apksigner.bat (最終調(diào)用Android SDK/build-tools/sdk版本/lib/apksigner.jar)?

不管是apk包,還是jar包,本質(zhì)都是zip格式的壓縮包,所以它們的簽名過程都差不多(僅限V1簽名),?

以上兩個工具都可以對Android apk包進行簽名.

五、簽名中 MANIFEST.MF CERT.SF和 CERT.RSA是怎么生成的

首先來看一下這三個文件里面都保存了什么?

注:這幾個文件的生成過程見Android源碼里面的SignApk.java?,一篇文章,這篇文章里面是Android2.2的源碼里面的。但是每個Android版本的sdk中,在?SDK/build-tools/sdk版本/lib/apksigner.jar下也會有個簽名工具的jar包。也可以通過 jd-gui 工具反編譯每個sdk版本下面的?apksigner.jar?查看來分析簽名中以下三個文件的生成過程。

1. MANIFEST.MF

首先要明白,這個玩意不是Android搞出來,這個在java打成jar包的時候,就會存在這么個清單文件。而且這個文件的格式是固定的,java里面有個類能夠解析這個文件:java.util.jar.Manifest;?然后把這個文件拖到sublime里面打開(把我們的apk的后綴名改成zip,然后用解壓軟件解壓):?

manifest 文件的格式:?是很簡單的,每一行都是 名-值 對應(yīng)的:屬性名開頭,接著是 “:” ,然后是屬性值,每行最多72個字符,如果需要增加,你可以在下一行續(xù)行,續(xù)行以空格開頭,以空格開頭的行都會被視為前一行的續(xù)行,所有在開頭的屬性都是全局的。

manifest 文件的內(nèi)容:?

這里面內(nèi)容的含義是啥?其中Name 對應(yīng)的是apk包里面的所有文件的文件名,而SHA-256-Digest 是指的是這個文件的求的sha的值的Base64編碼。為了驗證我們拿解壓出來的?AndroidManifest.xml做個試驗。?

有兩步要做:?

1. 計算文件的hash的值?

怎么求這個文件的hash值呢。有兩種方式:自己造輪子,自己用Python,或者java或者shell,寫個計算文件hash值的工具類;另一種方式可以借助工具。這里我借助工具來看,這里有個在線網(wǎng)站?計算文件的hash的值,當(dāng)然除了這個還有很多別的工具只要能計算文件hash就行。然后把我們的文件?AndroidManifest.xml上傳上去得到如下結(jié)果:

MD5Hash833f7812f9f9c4c7d4de99aa39866515SHA1Hashd5bb8c084310a5993832bdeeec70ab917088aa8aSHA256Hashc3328e24fccba47c73adaaa13a1f9180d2388b42b2899169d628158ce4810c1e

這里計算出來的是hash的 16進制。觀察我們的MANIFEST.MF文件里面的兩行,里面的計算hash的一行發(fā)現(xiàn),用的是 sha 256 算法,并且是Base64編碼的,所以需要轉(zhuǎn)換:

Name:AndroidManifest.xmlSHA-256-Digest:wzKOJPzLpHxzraqhOh+RgNI4i0KyiZFp1igVjOSBDB4=

把計算出來的文件的hash的16進制的值轉(zhuǎn)成Base64的編碼?

注意Base64 僅僅是種編碼方式而已。?

現(xiàn)在要把c3328e24fccba47c73adaaa13a1f9180d2388b42b2899169d628158ce4810c1e這個16進制轉(zhuǎn)換成Base64,方式同上也有兩種:自己寫代碼,借助工具。百度搜索16 進制轉(zhuǎn)base64?第一條就是個工具網(wǎng)站。轉(zhuǎn)換結(jié)果截圖如下:?

好到這里,就知道MANIFEST.MF 這個文件里面每一組內(nèi)容的來源了。可以依次驗證剩下的所有的文件的hash。

2. CERT.SF

這個文件其實也是一個Manifest文件格式的文件,同樣可以拖到sublime里面看一下。

其實對比上面 MANIFEST.MF 里面的每一組數(shù)據(jù),發(fā)現(xiàn),Name行是一一對應(yīng)的。只不過SHA-256-Digest行不同而已,那么這一行又是怎么算出來的。這里看前面給出的SignApk.java?的源碼。里面又這個文件的生成過程(包含了三個回車換行符”\r\n”)。就是把MANIFEST.MF 里面的每一組計算hash。但是這個每一組有點特殊。在源碼里面大約在397行:

/** Write a .SF file with a digest of the specified manifest. */private static void writeSignatureFile(Manifest manifest, OutputStreamout,? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? int hash)? ? ? ? throws IOException, GeneralSecurityException {? ? ? ? Manifest sf = new Manifest();Attributes main = sf.getMainAttributes();//構(gòu)建CERT.SF頭部的四行? ? ? ? main.putValue("Signature-Version","1.0");main.putValue("Created-By","1.0 (Android SignApk)");MessageDigest md = MessageDigest.getInstance(? ? ? ? ? ? hash == USE_SHA256 ?"SHA256":"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(hash == USE_SHA256 ?"SHA-256-Digest-Manifest":"SHA1-Digest-Manifest",? ? ? ? ? ? ? ? ? ? ? new String(Base64.encode(md.digest()),"ASCII"));Map entries = manifest.getEntries();//開始循環(huán)讀入MANIFEST.MF頭一下的每一組數(shù)據(jù),計算hash,并寫入CERT.SF中? ? ? ? for (Map.Entry entry : entries.entrySet()) {? ? ? ? ? ? // Digest of the manifest stanza for this entry.? ? ? ? ? ? print.print("Name: "+ entry.getKey() +"\r\n");for (Map.Entry att : entry.getValue().entrySet()) {? ? ? ? ? ? ? ? print.print(att.getKey() +": "+ att.getValue() +"\r\n");}? ? ? ? ? ? print.print("\r\n");print.flush();Attributes sfAttr = new Attributes();sfAttr.putValue(hash == USE_SHA256 ?"SHA-256-Digest":"SHA1-Digest-Manifest",? ? ? ? ? ? ? ? ? ? ? ? ? ? new String(Base64.encode(md.digest()),"ASCII"));sf.getEntries().put(entry.getKey(), sfAttr);}? ? ? ? CountOutputStream cout = new CountOutputStream(out);sf.write(cout);if ((cout.size() %1024) ==0) {? ? ? ? ? ? cout.write('\r');cout.write('\n');}? ? }

注:關(guān)于回車換行符,換行符‘\n’和回車符‘\r’。Windows系統(tǒng)里,文件每行結(jié)尾是”<回車><換行>”“\r\n”;Unix系統(tǒng)里,文件每行結(jié)尾是”<換行>”,即’\n’。

從上面源碼中可以看到,我們要計算Name: AndroidManifest.xml這個條目在CERT.SF中對應(yīng)的條目的hash,必須要計算下面這些字符串的hash,其中包含了三個回車換行(注意是回車換行):?

為什么在這里不斷的重復(fù)這個回車換行呢。就是我們本來有個很簡單的方法,如果想要計算一段字符串的hash,可以把這段字符串copy到文件中,然后用錢買的工具去計算這個文件的hash,但是在Mac系統(tǒng)上出現(xiàn)一個致命的錯誤:就是在copy過程中回車換行符?\r\n中的 回車符\r?(ASCII 碼16進制為0D)丟了。這里我們先不深究這個回車換行的問題了。

同樣要計算這段字符串的hash也是兩種方式。既然我們借助工具可能存在問題,那么我們模仿SignApk.java?生成CERT.SF 的過程自己寫一段驗證代碼。這段代碼是Java的,不屬于Android,為了簡單我省去了異常檢測:

publicclassSHA256 {publicstaticvoidmain(String[] args) throws Exception {? ? ? ? BASE64Encoder base64Encoder =newBASE64Encoder();? ? ? ? MessageDigest md = MessageDigest.getInstance("SHA-256");? ? ? ? ByteArrayOutputStream outputStream =newByteArrayOutputStream();? ? ? ? outputStream.write(("Name: AndroidManifest.xml\r\n").getBytes());? ? ? ? outputStream.write(("SHA-256-Digest: wzKOJPzLpHxzraqhOh+RgNI4i0KyiZFp1igVjOSBDB4=\r\n").getBytes());? ? ? ? outputStream.write("\r\n".getBytes());byte[] hashSha256 = md.digest(outputStream.toByteArray());? ? ? ? String sha256Base64Str = base64Encoder.encode(hashSha256);? ? ? ? BigInteger bigInteger =newBigInteger(1, hashSha256);? ? ? ? System.out.println("生成的摘要Base64編碼:"+ sha256Base64Str);? ? ? ? System.out.println("生成的摘要16進制編碼:"+ bigInteger.toString(16));? ? }}

打印結(jié)果

生成的摘要Base64編碼:vsFKOu9AFKSRe1RzLHH3zTHrdLRo+ysSX8Lv1YKRaiM=生成的摘要16進制編碼:bec14a3aef4014a4917b54732c71f7cd31eb74b468fb2b125fc2efd582916a23

當(dāng)然我們也可以模仿SignApk.java的生成過程,對 MANIFEST.MF 里面的所有條目分析一遍,源碼在文末給出。

3. CERT.RSA

和簽名相關(guān)的apk里面的文件總共有三個,目前分析完了兩個了,還有一個,這個有點麻煩,我們把它也拖到sublime里面打開看一下,發(fā)現(xiàn)全是二進制。?


我們分別來對比?android-2.2.2_r1 和 android-6.0.0_r5源碼里面的SignApk.java 的源碼來觀察這個文件的生成過程,來確定這個文件到底是個啥?

其實前面的兩個截圖中完成的功能是相同的就是生成了CERT.RSA文件。只不過生成方式不同,在Android2.x版本的時候是用的java的sun.security.pkcs.*包里面的工具,生成的。但是在4.x之后開始使用了一個開源庫:官網(wǎng),?文檔?。上面的PKCS7的功能比較清晰簡單,就是是封裝了 PKCS7 格式的?CERT.RSA?文件里面該有的內(nèi)容??梢钥吹竭@個文件從上往下總共包含四塊內(nèi)容:?

前面兩塊我們不用太關(guān)心,主要看最后兩塊,一個是1到多張公鑰證書,一個是n條加密后的消息摘要。

下面來看一下每一個X509公鑰證書包含哪些內(nèi)容(圖片來自互聯(lián)網(wǎng),稍作修改):?


證書就是普通的我們常見的公鑰證書的二進制格式而已,所以沒有什么好討論的,不過是從keystore里面導(dǎo)出的而已,可以自己驗證一下,通過命令行工具從keystore里面導(dǎo)出公鑰證書,然后拿到16進制字節(jié)碼從CERT.RSA里面查找是不是能找到相應(yīng)的片段。

但是最后一個SingerInfo對象表示的是啥?去看這個類的源碼,里面有個很重要的方法getEncryptedDigest?這里面存放的是真正的文件簽名,那么是哪個文件的簽名,是 CERT.SF 的。他在源碼里面用了個 FilterOutputStream的子類對象,在生成 CERT.SF 的時候,把寫的文件流字節(jié)數(shù)組也進行了簽名。然后保存到SingerInfo 對象里面,最后一塊寫入到CERT.RSA文件里面。我們反向操作,把這個簽名的數(shù)組給搞出來:

import sun.security.pkcs.PKCS7;import sun.security.pkcs.SignerInfo;import sun.security.x509.AlgorithmId;import java.io.File;import java.io.FileInputStream;import java.io.IOException;import java.math.BigInteger;import java.security.MessageDigest;import java.security.NoSuchAlgorithmException;import java.security.cert.CertificateException;import java.security.cert.X509Certificate;public class PKCS7Demo {? ? public static void main(String[] args) throws CertificateException, IOException, NoSuchAlgorithmException {? ? ? ? File file = new File("file/META-INF/CERT.RSA");FileInputStream fis = new FileInputStream(file);//通過java給提供的 PKCS7 工具類,解析CERT.RSA文件? ? ? ? PKCS7 pkcs7 = new PKCS7(fis);//然后提取AlgorithmId? ? ? ? AlgorithmId algorithmId = pkcs7.getDigestAlgorithmIds()[0];//然后提取 X509Certificate 所有的證書,但是我們只有一張證書? ? ? ? //這里為了簡單只去第一個就行了,每一個X509Certificate 代表一個證書? ? ? ? X509Certificate certificate = pkcs7.getCertificates()[0];//簽名者信息,最主要的是這個類里面的文件簽名,同樣只取一個? ? ? ? SignerInfo signerInfo = pkcs7.getSignerInfos()[0];System.out.println("algorithmId 16進制打印:"+ new BigInteger(1, algorithmId.encode()).toString(16));//? ? ? ? System.out.println("ContentInfo:"+ new BigInteger(1, contentInfo.getContent().getData()).toString(16));//編碼后的證書,下面的命令行可以導(dǎo)出? ? ? ? //$ openssl pkcs7 -inform DER -inCERT.RSA-print_certs | openssl x509 -outform DER -outCERT.cerSystem.out.println("第一張公鑰證書的16進制打印:"+ new BigInteger(1, certificate.getEncoded()).toString(16));// 對CERT.SF求摘要,然后加密后的東西放到這個里面? ? ? ? System.out.println("signerInfo 中保存的文件CERT.SF的加密簽名 16進制打印:"+ new BigInteger(1, signerInfo.getEncryptedDigest()).toString(16));//我要要獲取的簽名其實就是對整個證書 也就是certificate.getEncoded() 的摘要 md5,或者sha1? ? ? ? //其實從 keystore 里面導(dǎo)出證書,然后求md5和這個一樣? ? ? ? MessageDigest messageDigest = null;messageDigest = MessageDigest.getInstance("md5");// 計算md5函數(shù)? ? ? ? messageDigest.update(certificate.getEncoded());// digest()最后確定返回md5 hash值,返回值為8為字符串。因為md5 hash值是16位的hex值,實際上就是8位的字符? ? ? ? // BigInteger函數(shù)則將8位的字符串轉(zhuǎn)換成16位hex值,用字符串來表示;得到字符串形式的hash值? ? ? ? String hex = new BigInteger(1, messageDigest.digest()).toString(16);System.out.println("獲取apk簽名:"+ hex);}}

最終打印的結(jié)果

algorithmId16進制打印:300d06096086480165030402010500第一張公鑰證書的16進制打印:3082034d30820235a003020102020467617791300d06092a864886f70d01010b05003057310b30090603550406130230303110300e060355040813074265694a696e673110300e060355040713074265694a696e67310b3009060355040a13024141310b3009060355040b13024141310a30080603550403130151301e170d3138303332323038333430375a170d3433303331363038333430375a3057310b30090603550406130230303110300e060355040813074265694a696e673110300e060355040713074265694a696e67310b3009060355040a13024141310b3009060355040b13024141310a3008060355040313015130820122300d06092a864886f70d01010105000382010f003082010a02820101008f8dbba6345e60e716c9816507b06733ef4e6d94fa48e3075239fcfbfd60fd982176ff5583c877d9627f5bd047622fc80adffb91398fdb3b317825a845222ca580fdbb7f2a673d8f45340ef573cea72743c35a5fd94b9f23eac3079c1613f604e21317039b97956c9476f877cb3706c95c76c05bd1544fcdd337b000e007e31567c944f7f9b807029f4f68ebcc02db97d9e867bb0b31b2223a34cc27f2a57ef86db8b7160e283a5f1b33381e8edda7cae19c27efb8bfe75168a3abe4cfd83e45ef92c108be584753b5ffd90f5b686bd77303734e06dc4a827bed8cfca9a42ff41bbc703a9e2307313b2a6592cbe6226320bb7c8c4b481fe2b48448460fc0a59b0203010001a321301f301d0603551d0e041604148ab20e29227404298469eed528135bccf6c51551300d06092a864886f70d01010b05000382010100357c2094b085bdadaa7ac811c45765880f17496a75076514147a4ad8b9c8dc056f83cf81cda1b2b8904c7b79786e85aa1055abf56981dbadef549cd56b0d4a79d9280d3a39e00eac0614aef6b073beda7b13fd322b9a6d3a82ee987fcd166bb987dc2a173a2ac64a05b1c5b232a621ba45107517692bd7581236d5e21715ba45bc37b005fe8ca7edc124814cbc337736ca0851ead276c320f3034531fc8b479adb2aac2eb1836d6c9d4f3281a178ab3744a1f950db4fb6bd2572bcdf4f48deafdd31081d8c15c2bae4dc58040f643182f80d2455b690a909c074e7e58faae15f02020dc676508fd3727c611618ae0c590e2893afeaf30b75e318c3a0b1c99167signerInfo中保存的文件CERT.SF的加密簽名 16進制打印:33ab13d6cb6dbe350d28db217de7173bdbeb046095cd8e6b29bd34526350c56bb2ed4bb7fd528feac61b8c6da70eb688697b0be040a33a7377a2a179649f2aba1298e6ed0168243e122c6fb960d6c6186b1fb79166a70a1de9d224d48564a11e13c43db465521a59beab86c0f53c5e0dd2b1b86b1da92560acfa7842d4973481d4aa1f1efb15ad14e624b936738d8b44845202de6b97f4a40567b3657cefd8f03c25d75f00ab33b1d960ac5b38c26586c343fead3250a9fbfc010b01dafa47c3dc588c05885c485cfd8537a9d01c7ffd9606abf2bc7f176886a3128bbd7efbb07b195711e847c69cceb815ee198b0210e0918d0b7323896af0f3b17a3a8e17af獲取apk簽名:ec85ee04014aa1dff9857e08b4301fc8

然后我們借助一款工具(010Eidtor)來查看我們打印出來的這些16進制的東西,是不是正確的,工具主要是用來比對字節(jié)碼的,沒有工具也可以用眼看。在010Eidtor 里面搜索我們打印的證書或者簽名的16進制碼。發(fā)現(xiàn)確實能找到。?

到目前為止,我們成功的通過java的PKCS7的工具類,解析一下 apk里面生成的CERT.RSA這個文件。這個文件中大體包含了四塊有用的數(shù)據(jù)?,F(xiàn)在來看就剩下最后塊,簽名信息我們沒有驗證是怎么生成的了,從源碼來看,最后這一塊是把CERT.SF 這個文件,通過keystore里面的私鑰來計算簽名得到的。

兩個概念(前面有了,再寫一遍):

消息摘要:它是一個唯一對應(yīng)一個消息或文本的固定長度的值,它由一個單向Hash加密函數(shù)對消息進行作用而產(chǎn)生。如果消息在途中改變了,則接收者通過對收到消息的新產(chǎn)生的摘要與原摘要比較,就可知道消息是否被改變了。因此消息摘要保證了消息的完整性。消息摘要采用單向Hash 函數(shù)將需加密的明文”摘要”成一串密文,這一串密文亦稱為數(shù)字指紋(Finger Print)。它有固定的長度,且不同的明文摘要成密文,其結(jié)果總是不同的,而同樣的明文其摘要必定一致。這樣這串摘要便可成為驗證明文是否是”真身”的”指紋”了。

數(shù)字簽名:數(shù)字簽名算法可以看做是一種帶有密鑰的消息摘要算法,并且這種密鑰包含了公鑰和私鑰。也就是說,數(shù)字簽名算法是非對稱加密算法和消息摘要算法的結(jié)合體。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,565評論 6 539
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,115評論 3 423
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 177,577評論 0 382
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,514評論 1 316
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 72,234評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,621評論 1 326
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,641評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,822評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,380評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 41,128評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,319評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,879評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,548評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,970評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,229評論 1 291
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,048評論 3 397
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 48,285評論 2 376

推薦閱讀更多精彩內(nèi)容

  • 先說說這個經(jīng)典的案例旅行者困境。話說有兩個旅客丟了東西,都是花瓶。航空公司按規(guī)定最多賠100美金,又怕兩人私下串通...
    chentianlong閱讀 922評論 1 1
  • 電影的中文名字叫“無雙”,但片中的很多內(nèi)容都是“鏡像”出現(xiàn)的。“畫家”有一真一假,畫也有真品贗品,美金也分真鈔假鈔...
    孤勇與詞窮閱讀 438評論 0 0
  • 馬莊中心小學(xué) 五年級二班 王舒暢 我最喜歡的一句話是《滿江紅》中的這樣一句含義深刻的話:“莫等閑,白了少年頭,...
    王舒暢呀閱讀 224評論 0 1
  • 8月17日,環(huán)衛(wèi)局渣管科安排部署執(zhí)法人員45名,車輛12臺,采取設(shè)立檢查點和,24小時不間斷巡查的方式,檢...
    wuouwuouou閱讀 370評論 0 0
  • 參考地址:https://router.vuejs.org/zh-cn/ NPM安裝vue-router 使用 ....
    守心向暖閱讀 303評論 0 0