15d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov/* 25d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov * Copyright (C) 2016 The Android Open Source Project 35d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov * 45d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov * Licensed under the Apache License, Version 2.0 (the "License"); 55d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov * you may not use this file except in compliance with the License. 65d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov * You may obtain a copy of the License at 75d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov * 85d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov * http://www.apache.org/licenses/LICENSE-2.0 95d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov * 105d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov * Unless required by applicable law or agreed to in writing, software 115d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov * distributed under the License is distributed on an "AS IS" BASIS, 125d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 135d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov * See the License for the specific language governing permissions and 145d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov * limitations under the License. 155d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov */ 165d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov 175d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganovpackage android.util; 185d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov 195d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganovimport android.annotation.NonNull; 205d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganovimport android.annotation.Nullable; 215d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganovimport android.content.pm.Signature; 225d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov 23cdd685c07504223e37e7831ce592446ec4ac6f6aSvetoslav Ganovimport java.io.ByteArrayOutputStream; 24cdd685c07504223e37e7831ce592446ec4ac6f6aSvetoslav Ganovimport java.io.IOException; 255d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganovimport java.security.MessageDigest; 265d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganovimport java.security.NoSuchAlgorithmException; 27cdd685c07504223e37e7831ce592446ec4ac6f6aSvetoslav Ganovimport java.util.Arrays; 285d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov 295d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov/** 305d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov * Helper functions applicable to packages. 315d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov * @hide 325d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov */ 335d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganovpublic final class PackageUtils { 345d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov 355d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov private PackageUtils() { 365d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov /* hide constructor */ 375d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov } 385d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov 395d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov /** 40cdd685c07504223e37e7831ce592446ec4ac6f6aSvetoslav Ganov * Computes the SHA256 digests of a list of signatures. Items in the 41cdd685c07504223e37e7831ce592446ec4ac6f6aSvetoslav Ganov * resulting array of hashes correspond to the signatures in the 42cdd685c07504223e37e7831ce592446ec4ac6f6aSvetoslav Ganov * input array. 43cdd685c07504223e37e7831ce592446ec4ac6f6aSvetoslav Ganov * @param signatures The signatures. 44cdd685c07504223e37e7831ce592446ec4ac6f6aSvetoslav Ganov * @return The digest array. 455d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov */ 46cdd685c07504223e37e7831ce592446ec4ac6f6aSvetoslav Ganov public static @NonNull String[] computeSignaturesSha256Digests( 47cdd685c07504223e37e7831ce592446ec4ac6f6aSvetoslav Ganov @NonNull Signature[] signatures) { 48cdd685c07504223e37e7831ce592446ec4ac6f6aSvetoslav Ganov final int signatureCount = signatures.length; 49cdd685c07504223e37e7831ce592446ec4ac6f6aSvetoslav Ganov final String[] digests = new String[signatureCount]; 50cdd685c07504223e37e7831ce592446ec4ac6f6aSvetoslav Ganov for (int i = 0; i < signatureCount; i++) { 51cdd685c07504223e37e7831ce592446ec4ac6f6aSvetoslav Ganov digests[i] = computeSha256Digest(signatures[i].toByteArray()); 52cdd685c07504223e37e7831ce592446ec4ac6f6aSvetoslav Ganov } 53cdd685c07504223e37e7831ce592446ec4ac6f6aSvetoslav Ganov return digests; 54cdd685c07504223e37e7831ce592446ec4ac6f6aSvetoslav Ganov } 55cdd685c07504223e37e7831ce592446ec4ac6f6aSvetoslav Ganov /** 56cdd685c07504223e37e7831ce592446ec4ac6f6aSvetoslav Ganov * Computes a SHA256 digest of the signatures' SHA256 digests. First, 57cdd685c07504223e37e7831ce592446ec4ac6f6aSvetoslav Ganov * individual hashes for each signature is derived in a hexademical 58cdd685c07504223e37e7831ce592446ec4ac6f6aSvetoslav Ganov * form, then these strings are sorted based the natural ordering, and 59cdd685c07504223e37e7831ce592446ec4ac6f6aSvetoslav Ganov * finally a hash is derived from these strings' bytes. 60cdd685c07504223e37e7831ce592446ec4ac6f6aSvetoslav Ganov * @param signatures The signatures. 61cdd685c07504223e37e7831ce592446ec4ac6f6aSvetoslav Ganov * @return The digest. 62cdd685c07504223e37e7831ce592446ec4ac6f6aSvetoslav Ganov */ 63cdd685c07504223e37e7831ce592446ec4ac6f6aSvetoslav Ganov public static @NonNull String computeSignaturesSha256Digest( 64cdd685c07504223e37e7831ce592446ec4ac6f6aSvetoslav Ganov @NonNull Signature[] signatures) { 65cdd685c07504223e37e7831ce592446ec4ac6f6aSvetoslav Ganov // Shortcut for optimization - most apps singed by a single cert 66cdd685c07504223e37e7831ce592446ec4ac6f6aSvetoslav Ganov if (signatures.length == 1) { 67cdd685c07504223e37e7831ce592446ec4ac6f6aSvetoslav Ganov return computeSha256Digest(signatures[0].toByteArray()); 685d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov } 69cdd685c07504223e37e7831ce592446ec4ac6f6aSvetoslav Ganov 70cdd685c07504223e37e7831ce592446ec4ac6f6aSvetoslav Ganov // Make sure these are sorted to handle reversed certificates 71cdd685c07504223e37e7831ce592446ec4ac6f6aSvetoslav Ganov final String[] sha256Digests = computeSignaturesSha256Digests(signatures); 72cdd685c07504223e37e7831ce592446ec4ac6f6aSvetoslav Ganov return computeSignaturesSha256Digest(sha256Digests); 735d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov } 745d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov 755d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov /** 76cdd685c07504223e37e7831ce592446ec4ac6f6aSvetoslav Ganov * Computes a SHA256 digest in of the signatures SHA256 digests. First, 77cdd685c07504223e37e7831ce592446ec4ac6f6aSvetoslav Ganov * the strings are sorted based the natural ordering, and then a hash is 78cdd685c07504223e37e7831ce592446ec4ac6f6aSvetoslav Ganov * derived from these strings' bytes. 79cdd685c07504223e37e7831ce592446ec4ac6f6aSvetoslav Ganov * @param sha256Digests Signature SHA256 hashes in hexademical form. 80cdd685c07504223e37e7831ce592446ec4ac6f6aSvetoslav Ganov * @return The digest. 815d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov */ 82cdd685c07504223e37e7831ce592446ec4ac6f6aSvetoslav Ganov public static @NonNull String computeSignaturesSha256Digest( 83cdd685c07504223e37e7831ce592446ec4ac6f6aSvetoslav Ganov @NonNull String[] sha256Digests) { 84cdd685c07504223e37e7831ce592446ec4ac6f6aSvetoslav Ganov // Shortcut for optimization - most apps singed by a single cert 85cdd685c07504223e37e7831ce592446ec4ac6f6aSvetoslav Ganov if (sha256Digests.length == 1) { 86cdd685c07504223e37e7831ce592446ec4ac6f6aSvetoslav Ganov return sha256Digests[0]; 87cdd685c07504223e37e7831ce592446ec4ac6f6aSvetoslav Ganov } 88cdd685c07504223e37e7831ce592446ec4ac6f6aSvetoslav Ganov 89cdd685c07504223e37e7831ce592446ec4ac6f6aSvetoslav Ganov // Make sure these are sorted to handle reversed certificates 90cdd685c07504223e37e7831ce592446ec4ac6f6aSvetoslav Ganov Arrays.sort(sha256Digests); 91cdd685c07504223e37e7831ce592446ec4ac6f6aSvetoslav Ganov 92cdd685c07504223e37e7831ce592446ec4ac6f6aSvetoslav Ganov final ByteArrayOutputStream bytes = new ByteArrayOutputStream(); 93cdd685c07504223e37e7831ce592446ec4ac6f6aSvetoslav Ganov for (String sha256Digest : sha256Digests) { 94cdd685c07504223e37e7831ce592446ec4ac6f6aSvetoslav Ganov try { 95cdd685c07504223e37e7831ce592446ec4ac6f6aSvetoslav Ganov bytes.write(sha256Digest.getBytes()); 96cdd685c07504223e37e7831ce592446ec4ac6f6aSvetoslav Ganov } catch (IOException e) { 97cdd685c07504223e37e7831ce592446ec4ac6f6aSvetoslav Ganov /* ignore - can't happen */ 98cdd685c07504223e37e7831ce592446ec4ac6f6aSvetoslav Ganov } 99cdd685c07504223e37e7831ce592446ec4ac6f6aSvetoslav Ganov } 100cdd685c07504223e37e7831ce592446ec4ac6f6aSvetoslav Ganov return computeSha256Digest(bytes.toByteArray()); 1015d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov } 1025d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov 1035d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov /** 1045d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov * Computes the SHA256 digest of some data. 1055d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov * @param data The data. 1065d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov * @return The digest or null if an error occurs. 1075d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov */ 1085cdda3425ccf3c62e400a1646615f4479a8266afDaniel Cashman public static @Nullable byte[] computeSha256DigestBytes(@NonNull byte[] data) { 1095d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov MessageDigest messageDigest; 1105d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov try { 1115d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov messageDigest = MessageDigest.getInstance("SHA256"); 1125d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov } catch (NoSuchAlgorithmException e) { 1135d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov /* can't happen */ 1145d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov return null; 1155d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov } 1165d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov 1175d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov messageDigest.update(data); 1185d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov 1195cdda3425ccf3c62e400a1646615f4479a8266afDaniel Cashman return messageDigest.digest(); 1205cdda3425ccf3c62e400a1646615f4479a8266afDaniel Cashman } 1215cdda3425ccf3c62e400a1646615f4479a8266afDaniel Cashman 1225cdda3425ccf3c62e400a1646615f4479a8266afDaniel Cashman /** 1235cdda3425ccf3c62e400a1646615f4479a8266afDaniel Cashman * Computes the SHA256 digest of some data. 1245cdda3425ccf3c62e400a1646615f4479a8266afDaniel Cashman * @param data The data. 1255cdda3425ccf3c62e400a1646615f4479a8266afDaniel Cashman * @return The digest or null if an error occurs. 1265cdda3425ccf3c62e400a1646615f4479a8266afDaniel Cashman */ 1275cdda3425ccf3c62e400a1646615f4479a8266afDaniel Cashman public static @Nullable String computeSha256Digest(@NonNull byte[] data) { 1285cdda3425ccf3c62e400a1646615f4479a8266afDaniel Cashman return ByteStringUtils.toHexString(computeSha256DigestBytes(data)); 1295d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov } 1305d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov} 131