package com.wj.dexknife.shell.apkparser.parser;
import com.wj.dexknife.shell.apkparser.bean.CertificateMeta;
import com.wj.dexknife.shell.apkparser.utils.Utils;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateEncodingException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;
import sun.security.pkcs.PKCS7;
//import sun.security.pkcs.PKCS7;
/**
* parser certificate info.
* One apk may have multi certificates(certificate chain).
*
* @author dongliu
*/
public class CertificateParser {
private InputStream in;
private List<CertificateMeta> certificateMetas;
public CertificateParser(InputStream in) {
this.in = new BufferedInputStream(in);
}
/**
* get certificate info
*
* @throws IOException
* @throws CertificateEncodingException
*/
public void parse() throws IOException, CertificateException {
PKCS7 pkcs7 = new PKCS7(Utils.toByteArray(in));
X509Certificate[] certificates = pkcs7.getCertificates();
certificateMetas = new ArrayList<>();
for (X509Certificate certificate : certificates) {
CertificateMeta certificateMeta = new CertificateMeta();
certificateMetas.add(certificateMeta);
byte[] bytes = certificate.getEncoded();
String certMd5 = md5Digest(bytes);
String publicKeyString = byteToHexString(bytes);
String certBase64Md5 = md5Digest(publicKeyString);
certificateMeta.setData(bytes);
certificateMeta.setCertBase64Md5(certBase64Md5);
certificateMeta.setCertMd5(certMd5);
certificateMeta.setStartDate(certificate.getNotBefore());
certificateMeta.setEndDate(certificate.getNotAfter());
certificateMeta.setSignAlgorithm(certificate.getSigAlgName());
certificateMeta.setSignAlgorithmOID(certificate.getSigAlgOID());
}
}
private String md5Digest(byte[] input) throws IOException {
MessageDigest digest = getDigest("Md5");
digest.update(input);
return getHexString(digest.digest());
}
private String md5Digest(String input) throws IOException {
MessageDigest digest = getDigest("Md5");
digest.update(input.getBytes(StandardCharsets.UTF_8));
return getHexString(digest.digest());
}
private String byteToHexString(byte[] bArray) {
StringBuilder sb = new StringBuilder(bArray.length);
String sTemp;
for (byte aBArray : bArray) {
sTemp = Integer.toHexString(0xFF & (char) aBArray);
if (sTemp.length() < 2) {
sb.append(0);
}
sb.append(sTemp.toUpperCase());
}
return sb.toString();
}
private String getHexString(byte[] digest) {
BigInteger bi = new BigInteger(1, digest);
return String.format("%032x", bi);
}
private MessageDigest getDigest(String algorithm) {
try {
return MessageDigest.getInstance(algorithm);
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e.getMessage());
}
}
public List<CertificateMeta> getCertificateMetas() {
return certificateMetas;
}
}