安卓签名文件及解析

1. Android Studio默认的apk打包文件地址

用户根目录/.android/debug.keystore

Android Studio - debug keystore

Where the debug.keystore in Android Studio

Eclipse ADT基本一致:Windows->Preference->Android->Build 可以查看

2. 通过keytool计算apk的签名

对于jdk7及以上版本可以直接通过如下命令

keytool -list -printcert -jarfile apk_file_path

如果有keystore文件

keytool -list -keystore file_path

 默认的debug.keystore密码为android

I have never set any passwords to my keystore and alias, so how are they created

如果知道keystore的alias和密码,可以显示更详细的信息

keytool -list -alias androiddebugkey -keystore debug.keystore -storepass android -keypass android -v

对于jdk7以下的版本,可以先解压apk,对目标文件META-INF/CERT.RSA计算签名 

keytool -printcert -file file_path

How to find out which key was used to sign an app

How to get the certificate signing information from an Android APK

How can I verify the authenticity of an APK file I downloaded(对RSA文件有个简短的介绍)

3. 在android运行时计算apk的签名

/*
standard MessageDigest algorithms:
MD5
SHA-1
SHA-256
 */
private String getCertificateFingerprint(Context mContext, String algorithm, String packageName) {
    PackageManager pm = mContext.getPackageManager();
    int flags = PackageManager.GET_SIGNATURES;
    PackageInfo packageInfo = null;
    try {
        packageInfo = pm.getPackageInfo(packageName, flags);
    } catch (PackageManager.NameNotFoundException e) {
        e.printStackTrace();
    }

    if (packageInfo == null)
        return null;

    Signature[] signatures = packageInfo.signatures;
    //此处我直接默认只有一个签名
    byte[] cert = signatures[0].toByteArray();
    InputStream input = new ByteArrayInputStream(cert);
    CertificateFactory cf = null;
    try {
        cf = CertificateFactory.getInstance("X509");
    } catch (CertificateException e) {
        e.printStackTrace();
    }

    if (cf == null)
        return null;

    X509Certificate c = null;
    try {
        c = (X509Certificate) cf.generateCertificate(input);
    } catch (CertificateException e) {
        e.printStackTrace();
    }

    if (c==null)
        return null;

    String hexString = null;
    try {
        MessageDigest md = MessageDigest.getInstance(algorithm);
        byte[] publicKey = md.digest(c.getEncoded());
        hexString = byte2HexFormatted(publicKey);
    } catch (NoSuchAlgorithmException e1) {
        e1.printStackTrace();
    } catch (CertificateEncodingException e) {
        e.printStackTrace();
    }
    return hexString;
}

public static String byte2HexFormatted(byte[] arr) {
    StringBuilder str = new StringBuilder(arr.length * 2);
    for (int i = 0; i < arr.length; i++) {
        String h = Integer.toHexString(arr[i]);
        int l = h.length();
        if (l == 1) h = "0" + h;
        if (l > 2) h = h.substring(l - 2, l);
        str.append(h.toUpperCase());
        if (i < (arr.length - 1)) str.append(':');
    }
    return str.toString();
}

Get certificate fingerprint from android app

How to read SHA and MD5 fingerprint programmatically in Android

第二个链接提及了一个开源项目 apk-parser

4. 直接通过java程序获取

1) 读取apk中的RSA签名文件

ZipFile zipFile = new ZipFile("demo-debug.apk_2.0.4.apk");

Enumeration<? extends ZipEntry> entries = zipFile.entries();

while(entries.hasMoreElements()){
    ZipEntry entry = entries.nextElement();
    if (entry.getName().endsWith("RSA")) {
        ZipEntry entry = entries.nextElement();
    	//TODO with  zipFile.getInputStream(entry)
    }
}

Read Content from Files which are inside Zip file

2) 计算RSA文件签名

public static String[] getSign(InputStream input, String algorithm) throws CertificateException, NoSuchAlgorithmException {
    CertificateFactory cf = CertificateFactory.getInstance("X509");
    
    Collection<? extends Certificate> c = cf.generateCertificates(input);
   
    Certificate[] certs = c.toArray(new Certificate[c.size()]);
    
    String[] hexString = new String[certs.length];
    
    for (int i=0; i<certs.length; i++) {
    	X509Certificate x509Cert = (X509Certificate)certs[i];
    	
        MessageDigest md = MessageDigest.getInstance(algorithm);
        byte[] publicKey = md.digest(x509Cert.getEncoded());
        //byte2HexFormatted和android那边的一致
        hexString[i] = byte2HexFormatted(publicKey);
    }
    
    return hexString;
}

 主要参考了java KeyTool源码,可以搜索printcert,其中printCertFromStream是主要需要关注的函数

private void printCertFromStream(InputStream in, PrintStream out)

相关的一个开源项目android-apk-parser 

相关推荐