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