package com.secspace.lib.common.utils;

import android.content.Context;
import android.content.pm.PackageManager;
import android.content.pm.Signature;
import android.os.Build;
import android.util.DisplayMetrics;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;

/**
 * Created by SKR-CYW on 2016/6/22.
 */
public class SignVerifyUtil {

    public static final String TAG = "SignVerifyManager";

    /**
     * 获取签名值
     *
     * @param context
     * @param apkPath
     * @return
     * @throws Exception
     */
    public static byte[] getApkSignatureMD5(Context context, String apkPath) throws Exception {
        String sign = null;
        Class clazz = Class.forName("android.content.pm.PackageParser");

        Object packageParser = getParserObject(clazz);
        Object packag = getPackage(context, clazz, packageParser, apkPath);

        Method collectCertificatesMethod = clazz.getMethod("collectCertificates", Class.forName("android.content.pm.PackageParser$Package"), int.class);
        collectCertificatesMethod.invoke(packageParser, packag, PackageManager.GET_SIGNATURES);
        Signature mSignatures[] = (Signature[]) packag.getClass().getField("mSignatures").get(packag);
        System.out.println("size:" + mSignatures.length);
        Signature apkSignature = mSignatures.length > 0 ? mSignatures[0] : null;
        return apkSignature.toByteArray();
    }

    private static Object getParserObject(Class clazz) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException {
        return Build.VERSION.SDK_INT >= 21 ? clazz.getConstructor().newInstance() : clazz.getConstructor(String.class).newInstance("");
    }

    private static Object getPackage(Context c, Class clazz, Object instance, String path) throws Exception {
        Object pkg = null;
        if (Build.VERSION.SDK_INT >= 21) {
            Method method = clazz.getMethod("parsePackage", File.class, int.class);
            pkg = method.invoke(instance, new File(path), 0x0004);
        } else {
            Method method = clazz.getMethod("parsePackage", File.class, String.class, DisplayMetrics.class, int.class);
            pkg = method.invoke(instance, new File(path), null, c.getResources().getDisplayMetrics(), 0x0004);
        }

        return pkg;
    }

    /**
     * 从证书中提取publickey
     *
     * @param b
     * @return
     * @throws Exception
     */
    public static String getAPKPublicKeyFromCer(byte[] b) throws Exception {
        return parseSignature(b);
    }


    /**
     * 解析证书中的公钥值
     *
     * @param signature
     * @return
     */
    public static String parseSignature(byte[] signature) {
        try {
            CertificateFactory certFactory = CertificateFactory
                    .getInstance("X.509");
            X509Certificate cert = (X509Certificate) certFactory
                    .generateCertificate(new ByteArrayInputStream(signature));
            return new String(Base64Coder.encode(cert.getPublicKey().getEncoded()));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 验证签名公钥是否匹配
     *
     * @param context
     * @param apkPath apk路径
     * @param pubKey  签名公钥
     * @return
     * @throws Exception
     */
    public static boolean verifySignature(Context context, String apkPath, String pubKey) throws Exception {
        String apkPublicKeyFromCer = getAPKPublicKeyFromCer(getApkSignatureMD5(context, apkPath));
        if (pubKey.equals(apkPublicKeyFromCer)) {
            return true;
        }
        return false;
    }
}
