• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 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.util;
18 
19 import android.annotation.NonNull;
20 import android.annotation.Nullable;
21 import android.content.pm.Signature;
22 
23 import java.io.ByteArrayOutputStream;
24 import java.io.IOException;
25 import java.security.MessageDigest;
26 import java.security.NoSuchAlgorithmException;
27 import java.util.Arrays;
28 
29 /**
30  * Helper functions applicable to packages.
31  * @hide
32  */
33 public final class PackageUtils {
34 
PackageUtils()35     private PackageUtils() {
36         /* hide constructor */
37     }
38 
39     /**
40      * Computes the SHA256 digests of a list of signatures. Items in the
41      * resulting array of hashes correspond to the signatures in the
42      * input array.
43      * @param signatures The signatures.
44      * @return The digest array.
45      */
computeSignaturesSha256Digests( @onNull Signature[] signatures)46     public static @NonNull String[] computeSignaturesSha256Digests(
47             @NonNull Signature[] signatures) {
48         final int signatureCount = signatures.length;
49         final String[] digests = new String[signatureCount];
50         for (int i = 0; i < signatureCount; i++) {
51             digests[i] = computeSha256Digest(signatures[i].toByteArray());
52         }
53         return digests;
54     }
55     /**
56      * Computes a SHA256 digest of the signatures' SHA256 digests. First,
57      * individual hashes for each signature is derived in a hexademical
58      * form, then these strings are sorted based the natural ordering, and
59      * finally a hash is derived from these strings' bytes.
60      * @param signatures The signatures.
61      * @return The digest.
62      */
computeSignaturesSha256Digest( @onNull Signature[] signatures)63     public static @NonNull String computeSignaturesSha256Digest(
64             @NonNull Signature[] signatures) {
65         // Shortcut for optimization - most apps singed by a single cert
66         if (signatures.length == 1) {
67             return computeSha256Digest(signatures[0].toByteArray());
68         }
69 
70         // Make sure these are sorted to handle reversed certificates
71         final String[] sha256Digests = computeSignaturesSha256Digests(signatures);
72         return computeSignaturesSha256Digest(sha256Digests);
73     }
74 
75     /**
76      * Computes a SHA256 digest in of the signatures SHA256 digests. First,
77      * the strings are sorted based the natural ordering, and then a hash is
78      * derived from these strings' bytes.
79      * @param sha256Digests Signature SHA256 hashes in hexademical form.
80      * @return The digest.
81      */
computeSignaturesSha256Digest( @onNull String[] sha256Digests)82     public static @NonNull String computeSignaturesSha256Digest(
83             @NonNull String[] sha256Digests) {
84         // Shortcut for optimization - most apps singed by a single cert
85         if (sha256Digests.length == 1) {
86             return sha256Digests[0];
87         }
88 
89         // Make sure these are sorted to handle reversed certificates
90         Arrays.sort(sha256Digests);
91 
92         final ByteArrayOutputStream bytes = new ByteArrayOutputStream();
93         for (String sha256Digest : sha256Digests) {
94             try {
95                 bytes.write(sha256Digest.getBytes());
96             } catch (IOException e) {
97                 /* ignore - can't happen */
98             }
99         }
100         return computeSha256Digest(bytes.toByteArray());
101     }
102 
103     /**
104      * Computes the SHA256 digest of some data.
105      * @param data The data.
106      * @return The digest or null if an error occurs.
107      */
computeSha256DigestBytes(@onNull byte[] data)108     public static @Nullable byte[] computeSha256DigestBytes(@NonNull byte[] data) {
109         MessageDigest messageDigest;
110         try {
111             messageDigest = MessageDigest.getInstance("SHA256");
112         } catch (NoSuchAlgorithmException e) {
113             /* can't happen */
114             return null;
115         }
116 
117         messageDigest.update(data);
118 
119         return messageDigest.digest();
120     }
121 
122     /**
123      * Computes the SHA256 digest of some data.
124      * @param data The data.
125      * @return The digest or null if an error occurs.
126      */
computeSha256Digest(@onNull byte[] data)127     public static @Nullable String computeSha256Digest(@NonNull byte[] data) {
128         return ByteStringUtils.toHexString(computeSha256DigestBytes(data));
129     }
130 }
131