| /* |
| * Copyright (C) 2016 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package android.util; |
| |
| import android.annotation.NonNull; |
| import android.annotation.Nullable; |
| import android.content.pm.Signature; |
| |
| import java.io.ByteArrayOutputStream; |
| import java.io.IOException; |
| import java.security.MessageDigest; |
| import java.security.NoSuchAlgorithmException; |
| import java.util.Arrays; |
| |
| /** |
| * Helper functions applicable to packages. |
| * @hide |
| */ |
| public final class PackageUtils { |
| |
| private PackageUtils() { |
| /* hide constructor */ |
| } |
| |
| /** |
| * Computes the SHA256 digests of a list of signatures. Items in the |
| * resulting array of hashes correspond to the signatures in the |
| * input array. |
| * @param signatures The signatures. |
| * @return The digest array. |
| */ |
| public static @NonNull String[] computeSignaturesSha256Digests( |
| @NonNull Signature[] signatures) { |
| final int signatureCount = signatures.length; |
| final String[] digests = new String[signatureCount]; |
| for (int i = 0; i < signatureCount; i++) { |
| digests[i] = computeSha256Digest(signatures[i].toByteArray()); |
| } |
| return digests; |
| } |
| /** |
| * Computes a SHA256 digest of the signatures' SHA256 digests. First, |
| * individual hashes for each signature is derived in a hexademical |
| * form, then these strings are sorted based the natural ordering, and |
| * finally a hash is derived from these strings' bytes. |
| * @param signatures The signatures. |
| * @return The digest. |
| */ |
| public static @NonNull String computeSignaturesSha256Digest( |
| @NonNull Signature[] signatures) { |
| // Shortcut for optimization - most apps singed by a single cert |
| if (signatures.length == 1) { |
| return computeSha256Digest(signatures[0].toByteArray()); |
| } |
| |
| // Make sure these are sorted to handle reversed certificates |
| final String[] sha256Digests = computeSignaturesSha256Digests(signatures); |
| return computeSignaturesSha256Digest(sha256Digests); |
| } |
| |
| /** |
| * Computes a SHA256 digest in of the signatures SHA256 digests. First, |
| * the strings are sorted based the natural ordering, and then a hash is |
| * derived from these strings' bytes. |
| * @param sha256Digests Signature SHA256 hashes in hexademical form. |
| * @return The digest. |
| */ |
| public static @NonNull String computeSignaturesSha256Digest( |
| @NonNull String[] sha256Digests) { |
| // Shortcut for optimization - most apps singed by a single cert |
| if (sha256Digests.length == 1) { |
| return sha256Digests[0]; |
| } |
| |
| // Make sure these are sorted to handle reversed certificates |
| Arrays.sort(sha256Digests); |
| |
| final ByteArrayOutputStream bytes = new ByteArrayOutputStream(); |
| for (String sha256Digest : sha256Digests) { |
| try { |
| bytes.write(sha256Digest.getBytes()); |
| } catch (IOException e) { |
| /* ignore - can't happen */ |
| } |
| } |
| return computeSha256Digest(bytes.toByteArray()); |
| } |
| |
| /** |
| * Computes the SHA256 digest of some data. |
| * @param data The data. |
| * @return The digest or null if an error occurs. |
| */ |
| public static @Nullable byte[] computeSha256DigestBytes(@NonNull byte[] data) { |
| MessageDigest messageDigest; |
| try { |
| messageDigest = MessageDigest.getInstance("SHA256"); |
| } catch (NoSuchAlgorithmException e) { |
| /* can't happen */ |
| return null; |
| } |
| |
| messageDigest.update(data); |
| |
| return messageDigest.digest(); |
| } |
| |
| /** |
| * Computes the SHA256 digest of some data. |
| * @param data The data. |
| * @return The digest or null if an error occurs. |
| */ |
| public static @Nullable String computeSha256Digest(@NonNull byte[] data) { |
| return ByteStringUtils.toHexString(computeSha256DigestBytes(data)); |
| } |
| } |