Android签名验证简介

来源:互联网 发布:淘宝产品摄影技巧大全 编辑:程序博客网 时间:2024/05/23 18:32

Android签名验证简介

    博客分类: 
  • JAVA
  • Android
 

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

通过其中的源码PackageParser.java (frameworks\base\core\java\android\content\pm)
我们大概就能知道其签名验证机制的验证过程。
其中主要涉及2个函数:
函数1
Java代码  收藏代码
  1. public boolean collectCertificates(Package pkg, int flags) {  
  2.         pkg.mSignatures = null;  
  3.   
  4.         WeakReference<byte[]> readBufferRef;  
  5.         byte[] readBuffer = null;  
  6.         synchronized (mSync) {  
  7.             readBufferRef = mReadBuffer;  
  8.             if (readBufferRef != null) {  
  9.                 mReadBuffer = null;  
  10.                 readBuffer = readBufferRef.get();  
  11.             }  
  12.             if (readBuffer == null) {  
  13.                 readBuffer = new byte[8192];  
  14.                 readBufferRef = new WeakReference<byte[]>(readBuffer);  
  15.             }  
  16.         }  
  17.   
  18.         try {  
  19.             JarFile jarFile = new JarFile(mArchiveSourcePath);  
  20.   
  21.             Certificate[] certs = null;  
  22.   
  23.             if ((flags&PARSE_IS_SYSTEM) != 0) {  
  24.                 // If this package comes from the system image, then we  
  25.                 // can trust it...  we'll just use the AndroidManifest.xml  
  26.                 // to retrieve its signatures, not validating all of the  
  27.                 // files.  
  28.                 JarEntry jarEntry = jarFile.getJarEntry(ANDROID_MANIFEST_FILENAME);  
  29.                 certs = loadCertificates(jarFile, jarEntry, readBuffer);  
  30.                 if (certs == null) {  
  31.                     Slog.e(TAG, "Package " + pkg.packageName  
  32.                             + " has no certificates at entry "  
  33.                             + jarEntry.getName() + "; ignoring!");  
  34.                     jarFile.close();  
  35.                     mParseError = PackageManager.INSTALL_PARSE_FAILED_NO_CERTIFICATES;  
  36.                     return false;  
  37.                 }  
  38.                 if (DEBUG_JAR) {  
  39.                     Slog.i(TAG, "File " + mArchiveSourcePath + ": entry=" + jarEntry  
  40.                             + " certs=" + (certs != null ? certs.length : 0));  
  41.                     if (certs != null) {  
  42.                         final int N = certs.length;  
  43.                         for (int i=0; i<N; i++) {  
  44.                             Slog.i(TAG, "  Public key: "  
  45.                                     + certs[i].getPublicKey().getEncoded()  
  46.                                     + " " + certs[i].getPublicKey());  
  47.                         }  
  48.                     }  
  49.                 }  
  50.             } else {  
  51.                 Enumeration<JarEntry> entries = jarFile.entries();  
  52.                 final Manifest manifest = jarFile.getManifest();  
  53.                 while (entries.hasMoreElements()) {  
  54.                     final JarEntry je = entries.nextElement();  
  55.                     if (je.isDirectory()) continue;  
  56.   
  57.                     final String name = je.getName();  
  58.   
  59.                     if (name.startsWith("META-INF/"))  
  60.                         continue;  
  61.   
  62.                     if (ANDROID_MANIFEST_FILENAME.equals(name)) {  
  63.                         final Attributes attributes = manifest.getAttributes(name);  
  64.                         pkg.manifestDigest = ManifestDigest.fromAttributes(attributes);  
  65.                     }  
  66.   
  67.                     final Certificate[] localCerts = loadCertificates(jarFile, je, readBuffer);  
  68.                     if (DEBUG_JAR) {  
  69.                         Slog.i(TAG, "File " + mArchiveSourcePath + " entry " + je.getName()  
  70.                                 + ": certs=" + certs + " ("  
  71.                                 + (certs != null ? certs.length : 0) + ")");  
  72.                     }  
  73.   
  74.                     if (localCerts == null) {  
  75.                         Slog.e(TAG, "Package " + pkg.packageName  
  76.                                 + " has no certificates at entry "  
  77.                                 + je.getName() + "; ignoring!");  
  78.                         jarFile.close();  
  79.                         mParseError = PackageManager.INSTALL_PARSE_FAILED_NO_CERTIFICATES;  
  80.                         return false;  
  81.                     } else if (certs == null) {  
  82.                         certs = localCerts;  
  83.                     } else {  
  84.                         // Ensure all certificates match.  
  85.                         for (int i=0; i<certs.length; i++) {  
  86.                             boolean found = false;  
  87.                             for (int j=0; j<localCerts.length; j++) {  
  88.                                 if (certs[i] != null &&  
  89.                                         certs[i].equals(localCerts[j])) {  
  90.                                     found = true;  
  91.                                     break;  
  92.                                 }  
  93.                             }  
  94.                             if (!found || certs.length != localCerts.length) {  
  95.                                 Slog.e(TAG, "Package " + pkg.packageName  
  96.                                         + " has mismatched certificates at entry "  
  97.                                         + je.getName() + "; ignoring!");  
  98.                                 jarFile.close();  
  99.                                 mParseError = PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES;  
  100.                                 return false;  
  101.                             }  
  102.                         }  
  103.                     }  
  104.                 }  
  105.             }  
  106.             jarFile.close();  
  107.   
  108.             synchronized (mSync) {  
  109.                 mReadBuffer = readBufferRef;  
  110.             }  
  111.   
  112.             if (certs != null && certs.length > 0) {  
  113.                 final int N = certs.length;  
  114.                 pkg.mSignatures = new Signature[certs.length];  
  115.                 for (int i=0; i<N; i++) {  
  116.                     pkg.mSignatures[i] = new Signature(  
  117.                             certs[i].getEncoded());  
  118.                 }  
  119.             } else {  
  120.                 Slog.e(TAG, "Package " + pkg.packageName  
  121.                         + " has no certificates; ignoring!");  
  122.                 mParseError = PackageManager.INSTALL_PARSE_FAILED_NO_CERTIFICATES;  
  123.                 return false;  
  124.             }  
  125.         } catch (CertificateEncodingException e) {  
  126.             Slog.w(TAG, "Exception reading " + mArchiveSourcePath, e);  
  127.             mParseError = PackageManager.INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING;  
  128.             return false;  
  129.         } catch (IOException e) {  
  130.             Slog.w(TAG, "Exception reading " + mArchiveSourcePath, e);  
  131.             mParseError = PackageManager.INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING;  
  132.             return false;  
  133.         } catch (RuntimeException e) {  
  134.             Slog.w(TAG, "Exception reading " + mArchiveSourcePath, e);  
  135.             mParseError = PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION;  
  136.             return false;  
  137.         }  
  138.   
  139.         return true;  
  140.     }  
 函数2
Java代码  收藏代码
  1. private Certificate[] loadCertificates(JarFile jarFile, JarEntry je,  
  2.             byte[] readBuffer) {  
  3.         try {  
  4.             // We must read the stream for the JarEntry to retrieve  
  5.             // its certificates.  
  6.             InputStream is = new BufferedInputStream(jarFile.getInputStream(je));  
  7.             while (is.read(readBuffer, 0, readBuffer.length) != -1) {  
  8.                 // not using  
  9.             }  
  10.             is.close();  
  11.             return je != null ? je.getCertificates() : null;  
  12.         } catch (IOException e) {  
  13.             Slog.w(TAG, "Exception reading " + je.getName() + " in "  
  14.                     + jarFile.getName(), e);  
  15.         } catch (RuntimeException e) {  
  16.             Slog.w(TAG, "Exception reading " + je.getName() + " in "  
  17.                     + jarFile.getName(), e);  
  18.         }  
  19.         return null;  
  20.     }  
 通过上面的代码,我们已经能够得到了签名的证书,通过证书我们就得到PublicKey,通过比较PublicKey我们就能比较签名是否一致,当然这里假设的是只有一个签名。
实例1
Java代码  收藏代码
  1. package edu.edut.robin.utils;  
  2.   
  3. import java.io.ByteArrayInputStream;  
  4. import java.io.IOException;  
  5. import java.io.InputStream;  
  6. import java.security.PublicKey;  
  7. import java.security.cert.Certificate;  
  8. import java.security.cert.CertificateFactory;  
  9. import java.security.cert.X509Certificate;  
  10. import java.util.jar.JarEntry;  
  11. import java.util.jar.JarFile;  
  12.   
  13. import android.content.Context;  
  14. import android.content.pm.PackageInfo;  
  15. import android.content.pm.PackageManager;  
  16. import android.content.pm.PackageManager.NameNotFoundException;  
  17. import android.util.Base64;  
  18.   
  19. public class SigntureUtil  
  20. {  
  21.     final static String TAG = "Signture";  
  22.   
  23.     public static String[] getPublicKeyString(PackageInfo pi)  
  24.     {  
  25.         PublicKey pubKeys[] = getPublicKey(pi);  
  26.         if (pubKeys == null || pubKeys.length == 0)  
  27.         {  
  28.             return null;  
  29.         }  
  30.         String[] strPubKeys = new String[pubKeys.length];  
  31.         for (int i = 0; i < pubKeys.length; i++)  
  32.             strPubKeys[i] = Base64.encodeToString(pubKeys[i].getEncoded(),  
  33.                     Base64.DEFAULT);  
  34.         return strPubKeys;  
  35.     }  
  36.   
  37.     private static PublicKey[] getPublicKey(PackageInfo pi)  
  38.     {  
  39.         try  
  40.         {  
  41.             if (pi.signatures == null || pi.signatures.length == 0)  
  42.             {  
  43.                 return null;  
  44.             }  
  45.             PublicKey[] publicKeys = new PublicKey[pi.signatures.length];  
  46.             for (int i = 0; i < publicKeys.length; i++)  
  47.             {  
  48.                 byte[] signature = pi.signatures[i].toByteArray();  
  49.                 CertificateFactory certFactory = CertificateFactory  
  50.                         .getInstance("X.509");  
  51.                 InputStream is = new ByteArrayInputStream(signature);  
  52.                 X509Certificate cert = (X509Certificate) certFactory  
  53.                         .generateCertificate(is);  
  54.   
  55.                 publicKeys[i] = cert.getPublicKey();  
  56.             }  
  57.         } catch (Exception ex)  
  58.         {  
  59.   
  60.         }  
  61.         return null;  
  62.     }  
  63.   
  64.     private static PublicKey[] getInstalledAppPublicKey(Context context,  
  65.             String packageName)  
  66.     {  
  67.         PackageManager pm = context.getPackageManager();  
  68.         PackageInfo pi;  
  69.         try  
  70.         {  
  71.             pi = pm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);  
  72.             if (pi != null && pi.versionName != null)  
  73.             {  
  74.                 return getPublicKey(pi);  
  75.             }  
  76.         } catch (NameNotFoundException e)  
  77.         {  
  78.             // not installed  
  79.             return null;  
  80.         } catch (Exception e)  
  81.         {  
  82.             e.printStackTrace();  
  83.         }  
  84.   
  85.         return null;  
  86.     }  
  87.   
  88.     private static Certificate[] loadCertificates(JarFile jarFile, JarEntry je)  
  89.     {  
  90.         try  
  91.         {  
  92.             // We must read the stream for the JarEntry to retrieve  
  93.             // its certificates.  
  94.             byte[] readBuffer = new byte[1024];  
  95.             InputStream is = jarFile.getInputStream(je);  
  96.             while (is.read(readBuffer, 0, readBuffer.length) != -1)  
  97.                 ;  
  98.             is.close();  
  99.   
  100.             return (je != null) ? je.getCertificates() : null;  
  101.         } catch (IOException e)  
  102.         {  
  103.             e.printStackTrace();  
  104.         }  
  105.         return null;  
  106.     }  
  107.   
  108.     public static boolean verifySignature(Context context, String packageName,  
  109.             String filePath)  
  110.     {  
  111.         boolean verifyed = true;  
  112.         try  
  113.         {  
  114.             PublicKey[] installedAppPubKeys = getInstalledAppPublicKey(context,  
  115.                     packageName);  
  116.             if (installedAppPubKeys == null||installedAppPubKeys.length==0)  
  117.             {  
  118.                 // package not installed  
  119.                 return true;  
  120.             }  
  121.             JarFile jarFile = new JarFile(filePath);  
  122.             verifyed = false;  
  123.             JarEntry je = jarFile.getJarEntry("classes.dex");  
  124.             Certificate[] certs = loadCertificates(jarFile, je);  
  125.             if (certs != null && certs.length > 0)  
  126.             {  
  127.                 for (int i = 0; i < certs.length; i++)  
  128.                 {  
  129.                     PublicKey pubKey = certs[i].getPublicKey();  
  130.                     for(int j=0;j<installedAppPubKeys.length;j++)  
  131.                     {  
  132.                         if (pubKey.equals(installedAppPubKeys[j]))  
  133.                         {  
  134.                             verifyed = true;  
  135.                             break;  
  136.                         }  
  137.                     }  
  138.                     if(verifyed)  
  139.                         break;  
  140.                 }  
  141.             } else  
  142.             {  
  143.                 verifyed = true;  
  144.             }  
  145.   
  146.             jarFile.close();  
  147.         } catch (Exception e)  
  148.         {  
  149.             verifyed = true;  
  150.         }  
  151.   
  152.         return verifyed;  
  153.     }  
  154.   
  155. }  
 关于数字签名的更多内容请阅读《数字签名简介
关于java本身的数字签名和数字证书请参考《Java中的数字签名和数字证书》和Jar文件的数字签名
结束
0 0
原创粉丝点击