获取APK签名证书的SHA1和MD5

代码说明一切,请直接阅读代码。

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私钥。转化后证书的指纹信息是一样的。提供个如何转化证书的链接 http://blog.csdn.net/ilittleone/article/details/17914995

说到这里,你应该明白了吧。

你可能感兴趣的:(获取APK签名证书的SHA1和MD5)