本文博客原文
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 ;}
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;}
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 ; } }