PackageInfo方式获取App签名信息(含MD5)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/BlogRecord/article/details/48447139

概述:


Android对每一个Apk文件都会进行签名,在Apk文件安装时,系统会对其签名信息进行比对,判断程序的完整性,从而决定该Apk文件是否可以安装,在一定程度上达到安全的目的。

如何获取App签名信息


本章主要通过PackageInfo获取,其他方式汇总会单独一章讲解


注(例):微信开放平台,需要填写App签名MD5
可以通过 签名工具Apk 获取
也可以通过 PackageInfo,CERT.RSA,keytool等进行获取

代码实现(PackageInfo方式)


package com.app.signatures;

import java.io.ByteArrayInputStream;
import java.security.MessageDigest;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;

import javax.security.auth.x500.X500Principal;

import android.content.pm.Signature;

/**
 * 签名信息
 */
public class SignaturesMsg {

    // 如需要小写则把ABCDEF改成小写
    private static final char HEX_DIGITS[] = { '0', '1', '2', '3', '4', '5',
            '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };

    /**
     * 检测应用程序是否是用"CN=Android Debug,O=Android,C=US"的debug信息来签名的
     * 判断签名是debug签名还是release签名
     */
    private final static X500Principal DEBUG_DN = new X500Principal(
            "CN=Android Debug,O=Android,C=US");

    /**
     * 进行转换
     */
    public static String toHexString(byte[] bData) {
        StringBuilder sb = new StringBuilder(bData.length * 2);
        for (int i = 0; i < bData.length; i++) {
            sb.append(HEX_DIGITS[(bData[i] & 0xf0) >>> 4]);
            sb.append(HEX_DIGITS[bData[i] & 0x0f]);
        }
        return sb.toString();
    }

    /**
     * 返回MD5
     */
    public static String signatureMD5(Signature[] signatures) {
        try {
            MessageDigest digest = MessageDigest.getInstance("MD5");
            if (signatures != null) {
                for (Signature s : signatures)
                    digest.update(s.toByteArray());
            }
            return toHexString(digest.digest());
        } catch (Exception e) {
            return "";
        }
    }

    /**
     * SHA1
     */
    public static String signatureSHA1(Signature[] signatures) {
        try {
            MessageDigest digest = MessageDigest.getInstance("SHA-1");
            if (signatures != null) {
                for (Signature s : signatures)
                    digest.update(s.toByteArray());
            }
            return toHexString(digest.digest());
        } catch (Exception e) {
            return "";
        }
    }

    /**
     * SHA256
     */
    public static String signatureSHA256(Signature[] signatures) {
        try {
            MessageDigest digest = MessageDigest.getInstance("SHA-256");
            if (signatures != null) {
                for (Signature s : signatures)
                    digest.update(s.toByteArray());
            }
            return toHexString(digest.digest());
        } catch (Exception e) {
            return "";
        }
    }

    /**
     * 判断签名是debug签名还是release签名
     * @return true = 开发(debug.keystore),false = 上线发布(非.android默认debug.keystore)
     */
    public static boolean isDebuggable(Signature[] signatures) {
        // 判断是否默认key(默认是)
        boolean debuggable = true;
        try {
            for (int i = 0, c = signatures.length; i < c; i++) {
                CertificateFactory cf = CertificateFactory.getInstance("X.509");
                ByteArrayInputStream stream = new ByteArrayInputStream(signatures[i].toByteArray());
                X509Certificate cert = (X509Certificate) cf.generateCertificate(stream);
                debuggable = cert.getSubjectX500Principal().equals(DEBUG_DN);
                if (debuggable) {
                    break;
                }
            }
        } catch (Exception e) {
        }
        return debuggable;
    }

    /**
     * 获取App 证书对象
     */
    public static X509Certificate getX509Certificate(Signature[] signatures){
        try {
            CertificateFactory cf = CertificateFactory.getInstance("X.509");
            ByteArrayInputStream stream = new ByteArrayInputStream(signatures[0].toByteArray());
            X509Certificate cert = (X509Certificate) cf.generateCertificate(stream);
            return cert; 
        } catch (Exception e) {
        }
        return null;
    }

    public static String signatureName(Signature[] signatures){
        try {
            for (int i = 0, c = signatures.length; i < c; i++) {
                CertificateFactory cf = CertificateFactory.getInstance("X.509");
                ByteArrayInputStream stream = new ByteArrayInputStream(signatures[i].toByteArray());
                X509Certificate cert = (X509Certificate) cf.generateCertificate(stream);

                String pubKey = cert.getPublicKey().toString();   //公钥
                String signNumber = cert.getSerialNumber().toString();
                System.out.println("signName:" + cert.getSigAlgName());//算法名
                System.out.println("pubKey:" + pubKey);
                System.out.println("signNumber:" + signNumber);//证书序列编号
                System.out.println("subjectDN:"+cert.getSubjectDN().toString());

                System.out.println(cert.getNotAfter() + "--" + cert.getNotBefore());
            }
        } catch (Exception e) {
        }
        return "";
    }
}
package com.app.signatures;

import java.util.ArrayList;
import java.util.List;

import android.os.Bundle;
import android.text.TextPaint;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.graphics.drawable.Drawable;

public class MainActivity extends Activity implements OnClickListener {

    // 当前上下文
    private Context mContext;
    // ================ 控件View ================
    // HintTv
    private TextView am_hint_tv;
    // 显示App信息
    private ListView am_listview;
    // ================ 其他对象  ================
    // 获取全部app信息
    private ArrayList<PackageInfo> listPInfos = new ArrayList<PackageInfo>();
    // 适配器
    private AppAdapter aAdapter;
    // 获取图片、应用名、包名  
    private PackageManager pManager;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mContext = MainActivity.this;
        // 初始化操作
        initViews();
        initValues();
        initListeners();
    }

    /**
     * 初始化控件
     */
    private void initViews() {
        am_hint_tv = (TextView) this.findViewById(R.id.am_hint_tv);
        am_listview = (ListView) this.findViewById(R.id.am_listview);
    }

    /**
     * 初始化数据
     */
    private void initValues() {
        // 字体加粗
        TextPaint tp = am_hint_tv.getPaint(); 
        tp.setFakeBoldText(true);
        // 初始化
        pManager = mContext.getPackageManager();
        // 初始化APP数据
        getAllApps();
        // 初始化适配器,并绑定
        aAdapter = new AppAdapter();
        am_listview.setAdapter(aAdapter);
    }

    /**
     * 初始化事件
     */
    private void initListeners() {
        am_listview.setOnItemClickListener(new OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> vAdapter, View view, int position,long id) {
                try {
                    // 原始的PackageInfo
                    PackageInfo oPInfo = listPInfos.get(position);
                    // 获取包名
                    String packName = oPInfo.applicationInfo.packageName;

                    Intent intent = new Intent(mContext,SignaturesActivity.class);
                    intent.putExtra("packName", packName);
                    mContext.startActivity(intent);
                } catch (Exception e) {
                    e.printStackTrace();
                    showToast("获取App信息失败");
                }
            }
        });
    }



    /**
     * 点击事件
     */
    @Override
    public void onClick(View v) {
        switch (v.getId()) {
        }
    }

    /**
     * 重写返回键
     */
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_BACK) {
            MainActivity.this.finish();
            return true;
        }
        return super.onKeyDown(keyCode, event);
    }

    @Override
    protected void onStart() {
        super.onStart();
    }

    @Override
    protected void onRestart() {
        super.onRestart();
    }

    @Override
    protected void onResume() {
        super.onResume();
    }

    @Override
    protected void onPause() {
        super.onPause();
    }

    @Override
    protected void onStop() {
        super.onStop();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
    }

    // =============================  其他操作  =============================
    /**
     * 获取全部app信息
     */
    @SuppressWarnings("static-access")
    public void getAllApps() {
        this.listPInfos.clear(); // 清空旧数据
        // 管理应用程序包
        PackageManager pManager = mContext.getPackageManager();
        // 获取手机内所有应用
        List<PackageInfo> packlist = pManager.getInstalledPackages(0);
        for (int i = 0; i < packlist.size(); i++) {
            PackageInfo pak = (PackageInfo) packlist.get(i);
            // 判断是否为非系统预装的应用程序
            // 这里还可以添加系统自带的,这里就先不添加了,如果有需要可以自己添加
            // if()里的值如果<=0则为自己装的程序,否则为系统工程自带
            if ((pak.applicationInfo.flags & pak.applicationInfo.FLAG_SYSTEM) <= 0) {
                // 添加自己已经安装的应用程序
                this.listPInfos.add(pak);
            }
        }
    }

    // =============================  适配器    =============================
    class AppAdapter extends BaseAdapter{

        @Override
        public int getCount() {
            return listPInfos.size();
        }

        @Override
        public PackageInfo getItem(int position) {
            return listPInfos.get(position);
        }

        @Override
        public long getItemId(int position) {
            return position;
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            ViewHolder holder = null;
            if (convertView == null) {
                // 导入XML
                convertView = LayoutInflater.from(mContext).inflate(R.layout.app_item, null);
                holder = new ViewHolder();
                convertView.setTag(holder);
                holder.ai_igview = (ImageView) convertView.findViewById(R.id.ai_igview);
                holder.ai_name_tv = (TextView) convertView.findViewById(R.id.ai_name_tv);
                holder.ai_pack_tv = (TextView) convertView.findViewById(R.id.ai_pack_tv);
            } else {
                holder = (ViewHolder) convertView.getTag();
            }
            // 获取App信息
            PackageInfo pInfo = this.getItem(position);
            // 包名
            String aPack = pInfo.applicationInfo.packageName;
            // app名
            String aName = pManager.getApplicationLabel(pInfo.applicationInfo).toString();
            // app图标
            Drawable aIcon = pManager.getApplicationIcon(pInfo.applicationInfo);
            // 设置显示信息
            holder.ai_igview.setImageDrawable(aIcon); // 设置图标
            holder.ai_name_tv.setText(aName); // 设置app名
            holder.ai_pack_tv.setText(aPack); // 设置pack名
            return convertView;
        }

        class ViewHolder {
            ImageView ai_igview;
            TextView ai_name_tv;
            TextView ai_pack_tv;
        }
    }

    // =================== 显示Dialog =====================
    private Toast mToast;
    private void showToast(String hint){
        if (mToast != null) {
            mToast.setText(hint);
        } else {
            mToast = Toast.makeText(mContext, hint, Toast.LENGTH_SHORT);
        }
        mToast.show();
    }
}
package com.app.signatures;

import java.security.cert.CertificateExpiredException;
import java.security.cert.CertificateNotYetValidException;
import java.security.cert.X509Certificate;
import java.text.SimpleDateFormat;

import android.os.Bundle;
import android.text.ClipboardManager;
import android.view.KeyEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.graphics.drawable.Drawable;

public class SignaturesActivity extends Activity implements OnClickListener {

    // 当前上下文
    private Context mContext;
    // ================ 控件View ================
    // 图片Logo
    private ImageView as_igview;
    // app名
    private TextView as_name_tv;
    // 包名
    private TextView as_pack_tv;
    // MD5
    private TextView as_md5_tv;
    // MD5 Linear 点击复制
    private LinearLayout as_md5_linear;
    // SHA1
    private TextView as_sha1_tv;
    // SHA1 Linear 点击复制
    private LinearLayout as_sha1_linear;
    // SHA256
    private TextView as_sha256_tv;
    // SHA256 Linear 点击复制
    private LinearLayout as_sha256_linear;
    // 签名有效期
    private TextView as_effective_tv;
    // 签名有效期 Linear 点击复制
    private LinearLayout as_effective_linear;
    // 判断签名有效期
    private TextView as_iseffective_tv;
    // 判断签名有效期 Linear 点击复制
    private LinearLayout as_iseffective_linear;
    // 证书发布方
    private TextView as_principal_tv;
    // 证书发布方 Linear 点击复制
    private LinearLayout as_principal_linear;
    // 证书版本号
    private TextView as_version_tv;
    // 证书版本号 Linear 点击复制
    private LinearLayout as_version_linear;
    // 证书算法名称
    private TextView as_sigalgname_tv;
    // 证书算法名称 Linear 点击复制
    private LinearLayout as_sigalgname_linear;
    // 证书算法OID
    private TextView as_sigalgoid_tv;
    // 证书算法OID Linear 点击复制
    private LinearLayout as_sigalgoid_linear;
    // 证书机器码
    private TextView as_serialnumber_tv;
    // 证书机器码 Linear 点击复制
    private LinearLayout as_serialnumber_linear;
    // 证书DER编码
    private TextView as_dercode_tv;
    // 证书DER编码 Linear 点击复制
    private LinearLayout as_dercode_linear;
    // ================ 其他对象  ================
    // 获取图片、应用名、包名  
    private PackageManager pManager;
    // 项目包名
    private String packName;
    // 格式化日期
    private SimpleDateFormat dFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_signatures);
        mContext = SignaturesActivity.this;

        Intent intent = this.getIntent();
        if(intent != null){
            packName = intent.getStringExtra("packName");
        } else {
            showToast("包名为null");
            this.finish();
        }
        // 初始化操作
        initViews();
        initValues();
        initListeners();
    }

    /**
     * 初始化控件
     */
    private void initViews() {
        as_igview = (ImageView) this.findViewById(R.id.as_igview);
        as_name_tv = (TextView) this.findViewById(R.id.as_name_tv);
        as_pack_tv = (TextView) this.findViewById(R.id.as_pack_tv);
        as_md5_tv = (TextView) this.findViewById(R.id.as_md5_tv);
        as_sha1_tv = (TextView) this.findViewById(R.id.as_sha1_tv);
        as_sha256_tv = (TextView) this.findViewById(R.id.as_sha256_tv);
        as_effective_tv = (TextView) this.findViewById(R.id.as_effective_tv);
        as_iseffective_tv = (TextView) this.findViewById(R.id.as_iseffective_tv);
        as_principal_tv = (TextView) this.findViewById(R.id.as_principal_tv);
        as_version_tv = (TextView) this.findViewById(R.id.as_version_tv);
        as_sigalgname_tv = (TextView) this.findViewById(R.id.as_sigalgname_tv);
        as_sigalgoid_tv = (TextView) this.findViewById(R.id.as_sigalgoid_tv);
        as_serialnumber_tv = (TextView) this.findViewById(R.id.as_serialnumber_tv);
        as_dercode_tv = (TextView) this.findViewById(R.id.as_dercode_tv);


        as_md5_linear = (LinearLayout) this.findViewById(R.id.as_md5_linear);
        as_sha1_linear = (LinearLayout) this.findViewById(R.id.as_sha1_linear);
        as_sha256_linear = (LinearLayout) this.findViewById(R.id.as_sha256_linear);
        as_effective_linear = (LinearLayout) this.findViewById(R.id.as_effective_linear);
        as_iseffective_linear = (LinearLayout) this.findViewById(R.id.as_iseffective_linear);
        as_principal_linear = (LinearLayout) this.findViewById(R.id.as_principal_linear);
        as_version_linear = (LinearLayout) this.findViewById(R.id.as_version_linear);
        as_sigalgname_linear = (LinearLayout) this.findViewById(R.id.as_sigalgname_linear);
        as_sigalgoid_linear = (LinearLayout) this.findViewById(R.id.as_sigalgoid_linear);
        as_serialnumber_linear = (LinearLayout) this.findViewById(R.id.as_serialnumber_linear);
        as_dercode_linear = (LinearLayout) this.findViewById(R.id.as_dercode_linear);
    }

    /**
     * 初始化数据
     */
    private void initValues() {
        // 初始化
        pManager = mContext.getPackageManager();
        try {
            // 获取对应的PackageInfo(原始的PackageInfo 获取 signatures 等于null,需要这样获取)
            PackageInfo pInfo = pManager.getPackageInfo(packName, 64);
            // 包名
            String aPack = pInfo.applicationInfo.packageName;
            // app名
            String aName = pManager.getApplicationLabel(pInfo.applicationInfo).toString();
            // app图标
            Drawable aIcon = pManager.getApplicationIcon(pInfo.applicationInfo);
            // 设置显示信息
            as_igview.setImageDrawable(aIcon); // 设置图标
            as_name_tv.setText(aName); // 设置app名
            as_pack_tv.setText(aPack); // 设置pack名
            as_md5_tv.setText(SignaturesMsg.signatureMD5(pInfo.signatures)); // 设置MD5
            as_sha1_tv.setText(SignaturesMsg.signatureSHA1(pInfo.signatures)); // 设置SHA1
            as_sha256_tv.setText(SignaturesMsg.signatureSHA256(pInfo.signatures)); // 设置SHA256
            // 获取证书对象
            X509Certificate cert = SignaturesMsg.getX509Certificate(pInfo.signatures);
            // 设置有效期
            StringBuilder sbEffective = new StringBuilder();
            sbEffective.append(dFormat.format(cert.getNotBefore()));
            sbEffective.append("\t至\t");
            sbEffective.append(dFormat.format(cert.getNotAfter()));
            sbEffective.append("\n\n");
            sbEffective.append(cert.getNotBefore());
            sbEffective.append("\t至\t");
            sbEffective.append(cert.getNotAfter());
            as_effective_tv.setText(sbEffective.toString());
            // 证书是否过期 true = 过期,false = 未过期
            boolean isEffective = false;
            try {
                cert.checkValidity();
                // CertificateExpiredException - 如果证书已过期。
                // CertificateNotYetValidException - 如果证书不再有效。
            } catch (CertificateExpiredException ce) {
                isEffective = true;
            } catch (CertificateNotYetValidException ce) {
                isEffective = true;
            }
            as_iseffective_tv.setText(isEffective?getString(R.string.overdue_hint_s):getString(R.string.notoverdue_hint_s));
            // 证书发布方
            String principal = cert.getIssuerX500Principal().toString();
            as_principal_tv.setText(principal);
            // 证书版本号
            as_version_tv.setText(cert.getVersion()+"");
            // 证书算法名称
            as_sigalgname_tv.setText(cert.getSigAlgName());
            // 证书算法OID
            as_sigalgoid_tv.setText(cert.getSigAlgOID());
            // 证书机器码
            as_serialnumber_tv.setText(cert.getSerialNumber().toString());
            // 证书 DER编码
            as_dercode_tv.setText(SignaturesMsg.toHexString(cert.getTBSCertificate()));


            // 获取证书发行者   可根据证书发行者来判断该应用是否被二次打包(被破解的应用重新打包后,签名与原包一定不同,据此可以判断出该应用是否被人做过改动)
            // String[] certMsg = new String[2];
            // certMsg[0] = cert.getIssuerDN().toString();
            // certMsg[1] = cert.getSubjectDN().toString();
        } catch (Exception e) {
            e.printStackTrace();
            showToast("获取异常:" + e.toString());
        }
    }

    /**
     * 初始化事件
     */
    private void initListeners() {
        as_md5_linear.setOnClickListener(this);
        as_sha1_linear.setOnClickListener(this);
        as_sha256_linear.setOnClickListener(this);
        as_effective_linear.setOnClickListener(this);
        as_iseffective_linear.setOnClickListener(this);
        as_principal_linear.setOnClickListener(this);
        as_version_linear.setOnClickListener(this);
        as_sigalgname_linear.setOnClickListener(this);
        as_sigalgoid_linear.setOnClickListener(this);
        as_serialnumber_linear.setOnClickListener(this);
        as_dercode_linear.setOnClickListener(this);
    }



    /**
     * 点击事件
     */
    @Override
    public void onClick(View v) {
        switch (v.getId()) {
        case R.id.as_md5_linear:
            setClipboardText(as_md5_tv);
            break;
        case R.id.as_sha1_linear:
            setClipboardText(as_sha1_tv);
            break;
        case R.id.as_sha256_linear:
            setClipboardText(as_sha256_tv);
            break;
        case R.id.as_effective_linear:
            setClipboardText(as_effective_tv);
            break;
        case R.id.as_iseffective_linear:
            setClipboardText(as_iseffective_tv);
            break;
        case R.id.as_principal_linear:
            setClipboardText(as_principal_tv);
            break;
        case R.id.as_version_linear:
            setClipboardText(as_version_tv);
            break;
        case R.id.as_sigalgname_linear:
            setClipboardText(as_sigalgname_tv);
            break;
        case R.id.as_sigalgoid_linear:
            setClipboardText(as_sigalgoid_tv);
            break;
        case R.id.as_serialnumber_linear:
            setClipboardText(as_serialnumber_tv);
            break;
        case R.id.as_dercode_linear:
            setClipboardText(as_dercode_tv);
            break;
        }
    }

    /**
     * 重写返回键
     */
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_BACK) {
            SignaturesActivity.this.finish();
            return true;
        }
        return super.onKeyDown(keyCode, event);
    }

    @Override
    protected void onStart() {
        super.onStart();
    }

    @Override
    protected void onRestart() {
        super.onRestart();
    }

    @Override
    protected void onResume() {
        super.onResume();
    }

    @Override
    protected void onPause() {
        super.onPause();
    }

    @Override
    protected void onStop() {
        super.onStop();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
    }

    // =================== 显示Dialog =====================
    private Toast mToast;
    private void showToast(String hint){
        if (mToast != null) {
            mToast.setText(hint);
        } else {
            mToast = Toast.makeText(mContext, hint, Toast.LENGTH_SHORT);
        }
        mToast.show();
    }

    // ===================  复制到剪切板 =====================
    private void setClipboardText(TextView tv){
        ClipboardManager clip = (ClipboardManager)getSystemService(Context.CLIPBOARD_SERVICE);
        // 复制
        clip.setText(tv.getText().toString());
        // 提示
        showToast("已复制到剪切板");
    }
}

这里写图片描述

这里写图片描述

这里写图片描述


代码下载


闲着没事就写了一个Demo,以后自己要用也简单,需要的可以直接下载
获取App签名信息 - 379KB


参考:
- X509Certificate(API) - 证书的抽象类
- MD5转换
- PageageInfo 类


猜你喜欢

转载自blog.csdn.net/BlogRecord/article/details/48447139
今日推荐