代码说明一切,请直接阅读代码。
package com.mycompany.myapp5;import android.app.*;import android.content.pm.PackageInfo;import android.content.pm.PackageManager;import android.os.*;import android.widget.*;import java.io.*;import java.security.cert.CertificateFactory;import java.util.*;import java.security.cert.X509Certificate;import android.content.pm.*;import java.security.MessageDigest;import java.security.cert.*;public class MainActivity extends Activity { ByteArrayOutputStream bos=new ByteArrayOutputStream(); OutputStreamWriter osw=new OutputStreamWriter(bos); PrintWriter pw=new PrintWriter(osw, true); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ScrollView sv=new ScrollView(this); TextView tv=new TextView(this); sv.addView(tv); setContentView(sv); getCertMsg(this.getPackageName()); pw.flush(); tv.setText(bos.toString()); } private void getCertMsg(String packageName) { PackageInfo pis; try { pis = this.getPackageManager().getPackageInfo(packageName, PackageManager.GET_SIGNATURES); Signature[] sigs = pis.signatures; //签名 pw.println("sigs.len:" + sigs.length); pw.println("sigs[0] data:"); pw.println(toHex(sigs[0].toByteArray())); pw.println(); CertificateFactory certFactory = CertificateFactory.getInstance("X.509");//获取证书 X509Certificate cert = (X509Certificate) certFactory.generateCertificate( new ByteArrayInputStream(sigs[0].toByteArray()));//获取证书发行者 可根据证书发行者来判断该应用是否被二次打包(被破解的应用重新打包后,签名与原包一定不同,据此可以判断出该应用是否被人做过改动) pw.println("cert data:"); pw.println(toHex(cert.getEncoded())); pw.println(); MessageDigest sha1=MessageDigest.getInstance("SHA1"); byte[] bs=sha1.digest(cert.getEncoded()); String certSha1=toHex(bs); MessageDigest md5=MessageDigest.getInstance("md5"); byte[] bs2=md5.digest(cert.getEncoded()); String certMd5=toHex(bs2); pw.println("sha1:"); pw.println(certSha1); pw.println(); pw.println("md5"); pw.println(certMd5); pw.println(); pw.println(cert.getIssuerDN().toString()); pw.println(cert.getSubjectDN().toString()); } catch (CertificateException e) { e.printStackTrace(pw); } catch (Exception e) { e.printStackTrace(pw); } } char[] cs=new char[16]; { for (int i=0;i < 10;i++) { cs[i] = (char) ('0' + i); } for (int i=10;i < 16;i++) { cs[i] = (char) ('A' + i - 10); } } String toHex(byte[] bs) { char[] cs=new char[bs.length * 2]; int x; for (int i=0;i < bs.length;i++) { x = bs[i] & 0xff; cs[2 * i] = this.cs[x / 16]; cs[2 * i + 1] = this.cs[x % 16]; } return new String(cs); }}
上面的cert data=cert.getEncoded());
cert data就是pem文件的实际数据,也就是说,pem文件用的Base64编码,再转回byte[] 就是certdata了。
在上面的例子中,sigs[0].toByteArray()得到的数据和cert data是一样的,
再说说什么是pem文件,用过signApk工具的会在该工具的目录发现有两个文件,分别是.pem文件和.pk8文件
cert data等于.pem文件的内容的主体部分,也即是-----BEGIN CERTIFICATE-----和-----END CERTIFICATE-----
之间的部分,不包括这两个标记.BEGIN CERTIFICATE这个标记可能是其他相似的标记,openssl生产的就出现这种情况。对cert data SHA1摘要就和.pem公钥证书的SHA1指纹一样了,同理md5也一样。
看到这里,有人会问,我要的是 keystore证书的指纹,你怎么跟我讨论这个?
先别急,keystore证书的指纹和pem公钥证书的指纹是一样的,可以使用openssl将keystore的证书转成.pem公钥证书和.pk8私钥。转化后证书的指纹信息是一样的。提供个如何转化证书的链接
说到这里,你应该明白了吧。