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. C语言函数以及函数的使用
  2. ISurfaceComposer接口有13个成员函数
  3. Android jni系统变量、函数、接口定义汇总
  4. sscanf函数引起android 5.0卡死,C++中慎用C库函数
  5. Android实现自己的回调函数
  6. Android库so文件及skia函数的调用
  7. android读取keystore证书文件
  8. Android Camera源码函数结构
  9. 【Android自动化打包】03. APK的数字签名

随机推荐

  1. android SQLite 事物处理
  2. android拖动图片移动效果
  3. Android横向时间轴实现
  4. Android(安卓)support 26升级到28特性总
  5. android protobuf错误
  6. Android中如何获得本机号码信息
  7. Android(安卓)加载动画逐帧动画透明弹窗
  8. Android(安卓)Adapter
  9. [Android]ListView中分割线的设置
  10. Android中文SDK-----Android新手入门