Android原生自带了个安装器(packages\apps\PackageInstaller),

通过其中的源码 PackageParser.java (frameworks\base\core\java\android\content\pm) 我们大概就能知道其签名验证机制的验证过程。 其中主要涉及2个函数: 函数1
public boolean collectCertificates(Package pkg, int flags) {        pkg.mSignatures = null;        WeakReference<byte[]> readBufferRef;        byte[] readBuffer = null;        synchronized (mSync) {            readBufferRef = mReadBuffer;            if (readBufferRef != null) {                mReadBuffer = null;                readBuffer = readBufferRef.get();            }            if (readBuffer == null) {                readBuffer = new byte[8192];                readBufferRef = new WeakReference<byte[]>(readBuffer);            }        }        try {            JarFile jarFile = new JarFile(mArchiveSourcePath);            Certificate[] certs = null;            if ((flags&PARSE_IS_SYSTEM) != 0) {                // If this package comes from the system image, then we                // can trust it...  we'll just use the AndroidManifest.xml                // to retrieve its signatures, not validating all of the                // files.                JarEntry jarEntry = jarFile.getJarEntry(ANDROID_MANIFEST_FILENAME);                certs = loadCertificates(jarFile, jarEntry, readBuffer);                if (certs == null) {                    Slog.e(TAG, "Package " + pkg.packageName                            + " has no certificates at entry "                            + jarEntry.getName() + "; ignoring!");                    jarFile.close();                    mParseError = PackageManager.INSTALL_PARSE_FAILED_NO_CERTIFICATES;                    return false;                }                if (DEBUG_JAR) {                    Slog.i(TAG, "File " + mArchiveSourcePath + ": entry=" + jarEntry                            + " certs=" + (certs != null ? certs.length : 0));                    if (certs != null) {                        final int N = certs.length;                        for (int i=0; i<N; i++) {                            Slog.i(TAG, "  Public key: "                                    + certs[i].getPublicKey().getEncoded()                                    + " " + certs[i].getPublicKey());                        }                    }                }            } else {                Enumeration<JarEntry> entries = jarFile.entries();                final Manifest manifest = jarFile.getManifest();                while (entries.hasMoreElements()) {                    final JarEntry je = entries.nextElement();                    if (je.isDirectory()) continue;                    final String name = je.getName();                    if (name.startsWith("META-INF/"))                        continue;                    if (ANDROID_MANIFEST_FILENAME.equals(name)) {                        final Attributes attributes = manifest.getAttributes(name);                        pkg.manifestDigest = ManifestDigest.fromAttributes(attributes);                    }                    final Certificate[] localCerts = loadCertificates(jarFile, je, readBuffer);                    if (DEBUG_JAR) {                        Slog.i(TAG, "File " + mArchiveSourcePath + " entry " + je.getName()                                + ": certs=" + certs + " ("                                + (certs != null ? certs.length : 0) + ")");                    }                    if (localCerts == null) {                        Slog.e(TAG, "Package " + pkg.packageName                                + " has no certificates at entry "                                + je.getName() + "; ignoring!");                        jarFile.close();                        mParseError = PackageManager.INSTALL_PARSE_FAILED_NO_CERTIFICATES;                        return false;                    } else if (certs == null) {                        certs = localCerts;                    } else {                        // Ensure all certificates match.                        for (int i=0; i<certs.length; i++) {                            boolean found = false;                            for (int j=0; j<localCerts.length; j++) {                                if (certs[i] != null &&                                        certs[i].equals(localCerts[j])) {                                    found = true;                                    break;                                }                            }                            if (!found || certs.length != localCerts.length) {                                Slog.e(TAG, "Package " + pkg.packageName                                        + " has mismatched certificates at entry "                                        + je.getName() + "; ignoring!");                                jarFile.close();                                mParseError = PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES;                                return false;                            }                        }                    }                }            }            jarFile.close();            synchronized (mSync) {                mReadBuffer = readBufferRef;            }            if (certs != null && certs.length > 0) {                final int N = certs.length;                pkg.mSignatures = new Signature[certs.length];                for (int i=0; i<N; i++) {                    pkg.mSignatures[i] = new Signature(                            certs[i].getEncoded());                }            } else {                Slog.e(TAG, "Package " + pkg.packageName                        + " has no certificates; ignoring!");                mParseError = PackageManager.INSTALL_PARSE_FAILED_NO_CERTIFICATES;                return false;            }        } catch (CertificateEncodingException e) {            Slog.w(TAG, "Exception reading " + mArchiveSourcePath, e);            mParseError = PackageManager.INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING;            return false;        } catch (IOException e) {            Slog.w(TAG, "Exception reading " + mArchiveSourcePath, e);            mParseError = PackageManager.INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING;            return false;        } catch (RuntimeException e) {            Slog.w(TAG, "Exception reading " + mArchiveSourcePath, e);            mParseError = PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION;            return false;        }        return true;    }
函数2
private Certificate[] loadCertificates(JarFile jarFile, JarEntry je,            byte[] readBuffer) {        try {            // We must read the stream for the JarEntry to retrieve            // its certificates.            InputStream is = new BufferedInputStream(jarFile.getInputStream(je));            while (is.read(readBuffer, 0, readBuffer.length) != -1) {                // not using            }            is.close();            return je != null ? je.getCertificates() : null;        } catch (IOException e) {            Slog.w(TAG, "Exception reading " + je.getName() + " in "                    + jarFile.getName(), e);        } catch (RuntimeException e) {            Slog.w(TAG, "Exception reading " + je.getName() + " in "                    + jarFile.getName(), e);        }        return null;    }
通过上面的代码,我们已经能够得到了签名的证书,通过证书我们就得到PublicKey,通过比较PublicKey我们就能比较签名是否一致,当然这里假设的是只有一个签名。 实例1
package edu.edut.robin.utils;import java.io.ByteArrayInputStream;import java.io.IOException;import java.io.InputStream;import java.security.PublicKey;import java.security.cert.Certificate;import java.security.cert.CertificateFactory;import java.security.cert.X509Certificate;import java.util.jar.JarEntry;import java.util.jar.JarFile;import android.content.Context;import android.content.pm.PackageInfo;import android.content.pm.PackageManager;import android.content.pm.PackageManager.NameNotFoundException;import android.util.Base64;public class SigntureUtil{    final static String TAG = "Signture";    public static String[] getPublicKeyString(PackageInfo pi)    {        PublicKey pubKeys[] = getPublicKey(pi);        if (pubKeys == null || pubKeys.length == 0)        {            return null;        }        String[] strPubKeys = new String[pubKeys.length];        for (int i = 0; i < pubKeys.length; i++)            strPubKeys[i] = Base64.encodeToString(pubKeys[i].getEncoded(),                    Base64.DEFAULT);        return strPubKeys;    }    private static PublicKey[] getPublicKey(PackageInfo pi)    {        try        {            if (pi.signatures == null || pi.signatures.length == 0)            {                return null;            }            PublicKey[] publicKeys = new PublicKey[pi.signatures.length];            for (int i = 0; i < publicKeys.length; i++)            {                byte[] signature = pi.signatures[i].toByteArray();                CertificateFactory certFactory = CertificateFactory                        .getInstance("X.509");                InputStream is = new ByteArrayInputStream(signature);                X509Certificate cert = (X509Certificate) certFactory                        .generateCertificate(is);                publicKeys[i] = cert.getPublicKey();            }        } catch (Exception ex)        {        }        return null;    }    private static PublicKey[] getInstalledAppPublicKey(Context context,            String packageName)    {        PackageManager pm = context.getPackageManager();        PackageInfo pi;        try        {            pi = pm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);            if (pi != null && pi.versionName != null)            {                return getPublicKey(pi);            }        } catch (NameNotFoundException e)        {            // not installed            return null;        } catch (Exception e)        {            e.printStackTrace();        }        return null;    }    private static Certificate[] loadCertificates(JarFile jarFile, JarEntry je)    {        try        {            // We must read the stream for the JarEntry to retrieve            // its certificates.            byte[] readBuffer = new byte[1024];            InputStream is = jarFile.getInputStream(je);            while (is.read(readBuffer, 0, readBuffer.length) != -1)                ;            is.close();            return (je != null) ? je.getCertificates() : null;        } catch (IOException e)        {            e.printStackTrace();        }        return null;    }    public static boolean verifySignature(Context context, String packageName,            String filePath)    {        boolean verifyed = true;        try        {            PublicKey[] installedAppPubKeys = getInstalledAppPublicKey(context,                    packageName);            if (installedAppPubKeys == null||installedAppPubKeys.length==0)            {                // package not installed                return true;            }            JarFile jarFile = new JarFile(filePath);            verifyed = false;            JarEntry je = jarFile.getJarEntry("classes.dex");            Certificate[] certs = loadCertificates(jarFile, je);            if (certs != null && certs.length > 0)            {                for (int i = 0; i < certs.length; i++)                {                    PublicKey pubKey = certs[i].getPublicKey();                    for(int j=0;j<installedAppPubKeys.length;j++)                    {                        if (pubKey.equals(installedAppPubKeys[j]))                        {                            verifyed = true;                            break;                        }                    }                    if(verifyed)                        break;                }            } else            {                verifyed = true;            }            jarFile.close();        } catch (Exception e)        {            verifyed = true;        }        return verifyed;    }}
关于数字签名的更多内容请阅读《 数字签名简介 关于java本身的数字签名和数字证书请参考《 Java中的数字签名和数字证书 》和 Jar文件的数字签名 结束

更多相关文章

  1. [轉] android默认debug.keystore的密码
  2. android 纯c/c++开发
  3. Android的IPC机制Binder的详解(转发)
  4. Android中Message机制的灵活应用
  5. Android中获取屏幕相关信息(屏幕大小,状态栏、标题栏高度)
  6. 马达 vibrator的android的timed_output实现方式
  7. Android(安卓)jni系统变量、函数、接口定义汇总
  8. Android中Message机制的灵活应用
  9. Android(安卓)ViewPager的简单使用

随机推荐

  1. Android高性能文件类MemoryFile
  2. 巧用布局文件实现Android中实现事件监听
  3. intellij idea 设置用真机测试android
  4. Android大图片导致内存问题小结
  5. zxing二维码扫描的流程简析(Android版)
  6. 基于Android的传感器和语音识别的设计与
  7. Android2.2 API 中文文档系列(4) ―― Mani
  8. Android(安卓)小米盒子使用电视特性标签
  9. 【Android开发】多媒体应用开发-使用Medi
  10. Android(安卓)区别普通Touch方法和Scroll