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