PackageUtils.java revision 5d09c998a03eea53218c3b3c40e20db1b7693c9c
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.PackageInfo;
225d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganovimport android.content.pm.PackageManager;
235d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganovimport android.content.pm.Signature;
245d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov
255d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganovimport java.security.MessageDigest;
265d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganovimport java.security.NoSuchAlgorithmException;
275d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov
285d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov/**
295d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov * Helper functions applicable to packages.
305d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov * @hide
315d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov */
325d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganovpublic final class PackageUtils {
335d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov    private final static char[] HEX_ARRAY = "0123456789ABCDEF".toCharArray();
345d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov
355d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov    private PackageUtils() {
365d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov        /* hide constructor */
375d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov    }
385d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov
395d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov    /**
405d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov     * Computes the SHA256 digest of the signing cert for a package.
415d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov     * @param packageManager The package manager.
425d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov     * @param packageName The package for which to generate the digest.
435d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov     * @param userId The user for which to generate the digest.
445d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov     * @return The digest or null if the package does not exist for this user.
455d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov     */
465d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov    public static @Nullable String computePackageCertSha256Digest(
475d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov            @NonNull PackageManager packageManager,
485d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov            @NonNull String packageName, int userId) {
495d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov        final PackageInfo packageInfo;
505d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov        try {
515d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov            packageInfo = packageManager.getPackageInfoAsUser(packageName,
525d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov                    PackageManager.GET_SIGNATURES, userId);
535d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov        } catch (PackageManager.NameNotFoundException e) {
545d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov            return null;
555d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov        }
565d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov        return computeCertSha256Digest(packageInfo.signatures[0]);
575d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov    }
585d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov
595d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov    /**
605d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov     * Computes the SHA256 digest of a cert.
615d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov     * @param signature The signature.
625d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov     * @return The digest or null if an error occurs.
635d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov     */
645d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov    public static @Nullable String computeCertSha256Digest(@NonNull Signature signature) {
655d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov        return computeSha256Digest(signature.toByteArray());
665d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov    }
675d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov
685d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov    /**
695d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov     * Computes the SHA256 digest of some data.
705d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov     * @param data The data.
715d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov     * @return The digest or null if an error occurs.
725d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov     */
735d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov    public static @Nullable String computeSha256Digest(@NonNull byte[] data) {
745d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov        MessageDigest messageDigest;
755d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov        try {
765d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov            messageDigest = MessageDigest.getInstance("SHA256");
775d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov        } catch (NoSuchAlgorithmException e) {
785d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov            /* can't happen */
795d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov            return null;
805d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov        }
815d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov
825d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov        messageDigest.update(data);
835d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov
845d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov        final byte[] digest = messageDigest.digest();
855d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov        final int digestLength = digest.length;
865d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov        final int charCount = 2 * digestLength;
875d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov
885d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov        final char[] chars = new char[charCount];
895d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov        for (int i = 0; i < digestLength; i++) {
905d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov            final int byteHex = digest[i] & 0xFF;
915d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov            chars[i * 2] = HEX_ARRAY[byteHex >>> 4];
925d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov            chars[i * 2 + 1] = HEX_ARRAY[byteHex & 0x0F];
935d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov        }
945d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov        return new String(chars);
955d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov    }
965d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov}
97