• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2008 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.content.pm;
18 
19 import android.os.Parcel;
20 import android.os.Parcelable;
21 
22 import java.io.ByteArrayInputStream;
23 import java.lang.ref.SoftReference;
24 import java.security.PublicKey;
25 import java.security.cert.Certificate;
26 import java.security.cert.CertificateException;
27 import java.security.cert.CertificateFactory;
28 import java.util.Arrays;
29 
30 /**
31  * Opaque, immutable representation of a signature associated with an
32  * application package.
33  */
34 public class Signature implements Parcelable {
35     private final byte[] mSignature;
36     private int mHashCode;
37     private boolean mHaveHashCode;
38     private SoftReference<String> mStringRef;
39 
40     /**
41      * Create Signature from an existing raw byte array.
42      */
Signature(byte[] signature)43     public Signature(byte[] signature) {
44         mSignature = signature.clone();
45     }
46 
parseHexDigit(int nibble)47     private static final int parseHexDigit(int nibble) {
48         if ('0' <= nibble && nibble <= '9') {
49             return nibble - '0';
50         } else if ('a' <= nibble && nibble <= 'f') {
51             return nibble - 'a' + 10;
52         } else if ('A' <= nibble && nibble <= 'F') {
53             return nibble - 'A' + 10;
54         } else {
55             throw new IllegalArgumentException("Invalid character " + nibble + " in hex string");
56         }
57     }
58 
59     /**
60      * Create Signature from a text representation previously returned by
61      * {@link #toChars} or {@link #toCharsString()}. Signatures are expected to
62      * be a hex-encoded ASCII string.
63      *
64      * @param text hex-encoded string representing the signature
65      * @throws IllegalArgumentException when signature is odd-length
66      */
Signature(String text)67     public Signature(String text) {
68         final byte[] input = text.getBytes();
69         final int N = input.length;
70 
71         if (N % 2 != 0) {
72             throw new IllegalArgumentException("text size " + N + " is not even");
73         }
74 
75         final byte[] sig = new byte[N / 2];
76         int sigIndex = 0;
77 
78         for (int i = 0; i < N;) {
79             final int hi = parseHexDigit(input[i++]);
80             final int lo = parseHexDigit(input[i++]);
81             sig[sigIndex++] = (byte) ((hi << 4) | lo);
82         }
83 
84         mSignature = sig;
85     }
86 
87     /**
88      * Encode the Signature as ASCII text.
89      */
toChars()90     public char[] toChars() {
91         return toChars(null, null);
92     }
93 
94     /**
95      * Encode the Signature as ASCII text in to an existing array.
96      *
97      * @param existingArray Existing char array or null.
98      * @param outLen Output parameter for the number of characters written in
99      * to the array.
100      * @return Returns either <var>existingArray</var> if it was large enough
101      * to hold the ASCII representation, or a newly created char[] array if
102      * needed.
103      */
toChars(char[] existingArray, int[] outLen)104     public char[] toChars(char[] existingArray, int[] outLen) {
105         byte[] sig = mSignature;
106         final int N = sig.length;
107         final int N2 = N*2;
108         char[] text = existingArray == null || N2 > existingArray.length
109                 ? new char[N2] : existingArray;
110         for (int j=0; j<N; j++) {
111             byte v = sig[j];
112             int d = (v>>4)&0xf;
113             text[j*2] = (char)(d >= 10 ? ('a' + d - 10) : ('0' + d));
114             d = v&0xf;
115             text[j*2+1] = (char)(d >= 10 ? ('a' + d - 10) : ('0' + d));
116         }
117         if (outLen != null) outLen[0] = N;
118         return text;
119     }
120 
121     /**
122      * Return the result of {@link #toChars()} as a String.
123      */
toCharsString()124     public String toCharsString() {
125         String str = mStringRef == null ? null : mStringRef.get();
126         if (str != null) {
127             return str;
128         }
129         str = new String(toChars());
130         mStringRef = new SoftReference<String>(str);
131         return str;
132     }
133 
134     /**
135      * @return the contents of this signature as a byte array.
136      */
toByteArray()137     public byte[] toByteArray() {
138         byte[] bytes = new byte[mSignature.length];
139         System.arraycopy(mSignature, 0, bytes, 0, mSignature.length);
140         return bytes;
141     }
142 
143     /**
144      * Returns the public key for this signature.
145      *
146      * @throws CertificateException when Signature isn't a valid X.509
147      *             certificate; shouldn't happen.
148      * @hide
149      */
getPublicKey()150     public PublicKey getPublicKey() throws CertificateException {
151         final CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
152         final ByteArrayInputStream bais = new ByteArrayInputStream(mSignature);
153         final Certificate cert = certFactory.generateCertificate(bais);
154         return cert.getPublicKey();
155     }
156 
157     @Override
equals(Object obj)158     public boolean equals(Object obj) {
159         try {
160             if (obj != null) {
161                 Signature other = (Signature)obj;
162                 return this == other || Arrays.equals(mSignature, other.mSignature);
163             }
164         } catch (ClassCastException e) {
165         }
166         return false;
167     }
168 
169     @Override
hashCode()170     public int hashCode() {
171         if (mHaveHashCode) {
172             return mHashCode;
173         }
174         mHashCode = Arrays.hashCode(mSignature);
175         mHaveHashCode = true;
176         return mHashCode;
177     }
178 
describeContents()179     public int describeContents() {
180         return 0;
181     }
182 
writeToParcel(Parcel dest, int parcelableFlags)183     public void writeToParcel(Parcel dest, int parcelableFlags) {
184         dest.writeByteArray(mSignature);
185     }
186 
187     public static final Parcelable.Creator<Signature> CREATOR
188             = new Parcelable.Creator<Signature>() {
189         public Signature createFromParcel(Parcel source) {
190             return new Signature(source);
191         }
192 
193         public Signature[] newArray(int size) {
194             return new Signature[size];
195         }
196     };
197 
Signature(Parcel source)198     private Signature(Parcel source) {
199         mSignature = source.createByteArray();
200     }
201 }
202