FileDocCategorySizeDatePackage
Signature.javaAPI DocAndroid 5.1 API10060Thu Mar 12 22:22:10 GMT 2015android.content.pm

Signature

public class Signature extends Object implements android.os.Parcelable
Opaque, immutable representation of a signing certificate associated with an application package.

This class name is slightly misleading, since it's not actually a signature.

Fields Summary
private final byte[]
mSignature
private int
mHashCode
private boolean
mHaveHashCode
private SoftReference
mStringRef
private Certificate[]
mCertificateChain
public static final Parcelable.Creator
CREATOR
Constructors Summary
public Signature(byte[] signature)
Create Signature from an existing raw byte array.

        mSignature = signature.clone();
        mCertificateChain = null;
    
private Signature(android.os.Parcel source)


       
        mSignature = source.createByteArray();
    
public Signature(Certificate[] certificateChain)
Create signature from a certificate chain. Used for backward compatibility.

throws
CertificateEncodingException
hide

        mSignature = certificateChain[0].getEncoded();
        if (certificateChain.length > 1) {
            mCertificateChain = Arrays.copyOfRange(certificateChain, 1, certificateChain.length);
        }
    
public Signature(String text)
Create Signature from a text representation previously returned by {@link #toChars} or {@link #toCharsString()}. Signatures are expected to be a hex-encoded ASCII string.

param
text hex-encoded string representing the signature
throws
IllegalArgumentException when signature is odd-length

        final byte[] input = text.getBytes();
        final int N = input.length;

        if (N % 2 != 0) {
            throw new IllegalArgumentException("text size " + N + " is not even");
        }

        final byte[] sig = new byte[N / 2];
        int sigIndex = 0;

        for (int i = 0; i < N;) {
            final int hi = parseHexDigit(input[i++]);
            final int lo = parseHexDigit(input[i++]);
            sig[sigIndex++] = (byte) ((hi << 4) | lo);
        }

        mSignature = sig;
    
Methods Summary
public static booleanareEffectiveMatch(android.content.pm.Signature[] a, android.content.pm.Signature[] b)
Test if given {@link Signature} sets are effectively equal. In rare cases, certificates can have slightly malformed encoding which causes exact-byte checks to fail.

To identify effective equality, we bounce the certificates through an decode/encode pass before doing the exact-byte check. To reduce attack surface area, we only allow a byte size delta of a few bytes.

throws
CertificateException if the before/after length differs substantially, usually a signal of something fishy going on.
hide

        final CertificateFactory cf = CertificateFactory.getInstance("X.509");

        final Signature[] aPrime = new Signature[a.length];
        for (int i = 0; i < a.length; i++) {
            aPrime[i] = bounce(cf, a[i]);
        }
        final Signature[] bPrime = new Signature[b.length];
        for (int i = 0; i < b.length; i++) {
            bPrime[i] = bounce(cf, b[i]);
        }

        return areExactMatch(aPrime, bPrime);
    
public static booleanareExactMatch(android.content.pm.Signature[] a, android.content.pm.Signature[] b)
Test if given {@link Signature} sets are exactly equal.

hide

        return (a.length == b.length) && ArrayUtils.containsAll(a, b)
                && ArrayUtils.containsAll(b, a);
    
public static android.content.pm.Signaturebounce(java.security.cert.CertificateFactory cf, android.content.pm.Signature s)
Bounce the given {@link Signature} through a decode/encode cycle.

throws
CertificateException if the before/after length differs substantially, usually a signal of something fishy going on.
hide

        final InputStream is = new ByteArrayInputStream(s.mSignature);
        final X509Certificate cert = (X509Certificate) cf.generateCertificate(is);
        final Signature sPrime = new Signature(cert.getEncoded());

        if (Math.abs(sPrime.mSignature.length - s.mSignature.length) > 2) {
            throw new CertificateException("Bounced cert length looks fishy; before "
                    + s.mSignature.length + ", after " + sPrime.mSignature.length);
        }

        return sPrime;
    
public intdescribeContents()

        return 0;
    
public booleanequals(java.lang.Object obj)

        try {
            if (obj != null) {
                Signature other = (Signature)obj;
                return this == other || Arrays.equals(mSignature, other.mSignature);
            }
        } catch (ClassCastException e) {
        }
        return false;
    
public android.content.pm.Signature[]getChainSignatures()
Used for compatibility code that needs to check the certificate chain during upgrades.

throws
CertificateEncodingException
hide

        if (mCertificateChain == null) {
            return new Signature[] { this };
        }

        Signature[] chain = new Signature[1 + mCertificateChain.length];
        chain[0] = this;

        int i = 1;
        for (Certificate c : mCertificateChain) {
            chain[i++] = new Signature(c.getEncoded());
        }

        return chain;
    
public java.security.PublicKeygetPublicKey()
Returns the public key for this signature.

throws
CertificateException when Signature isn't a valid X.509 certificate; shouldn't happen.
hide

        final CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
        final ByteArrayInputStream bais = new ByteArrayInputStream(mSignature);
        final Certificate cert = certFactory.generateCertificate(bais);
        return cert.getPublicKey();
    
public inthashCode()

        if (mHaveHashCode) {
            return mHashCode;
        }
        mHashCode = Arrays.hashCode(mSignature);
        mHaveHashCode = true;
        return mHashCode;
    
private static final intparseHexDigit(int nibble)

        if ('0" <= nibble && nibble <= '9") {
            return nibble - '0";
        } else if ('a" <= nibble && nibble <= 'f") {
            return nibble - 'a" + 10;
        } else if ('A" <= nibble && nibble <= 'F") {
            return nibble - 'A" + 10;
        } else {
            throw new IllegalArgumentException("Invalid character " + nibble + " in hex string");
        }
    
public byte[]toByteArray()

return
the contents of this signature as a byte array.

        byte[] bytes = new byte[mSignature.length];
        System.arraycopy(mSignature, 0, bytes, 0, mSignature.length);
        return bytes;
    
public char[]toChars()
Encode the Signature as ASCII text.

        return toChars(null, null);
    
public char[]toChars(char[] existingArray, int[] outLen)
Encode the Signature as ASCII text in to an existing array.

param
existingArray Existing char array or null.
param
outLen Output parameter for the number of characters written in to the array.
return
Returns either existingArray if it was large enough to hold the ASCII representation, or a newly created char[] array if needed.

        byte[] sig = mSignature;
        final int N = sig.length;
        final int N2 = N*2;
        char[] text = existingArray == null || N2 > existingArray.length
                ? new char[N2] : existingArray;
        for (int j=0; j<N; j++) {
            byte v = sig[j];
            int d = (v>>4)&0xf;
            text[j*2] = (char)(d >= 10 ? ('a" + d - 10) : ('0" + d));
            d = v&0xf;
            text[j*2+1] = (char)(d >= 10 ? ('a" + d - 10) : ('0" + d));
        }
        if (outLen != null) outLen[0] = N;
        return text;
    
public java.lang.StringtoCharsString()
Return the result of {@link #toChars()} as a String.

        String str = mStringRef == null ? null : mStringRef.get();
        if (str != null) {
            return str;
        }
        str = new String(toChars());
        mStringRef = new SoftReference<String>(str);
        return str;
    
public voidwriteToParcel(android.os.Parcel dest, int parcelableFlags)

        dest.writeByteArray(mSignature);