1 /* 2 * Copyright (C) 2022 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 com.android.managedprovisioning.task; 18 19 import static java.util.Objects.requireNonNull; 20 21 import android.content.pm.PackageInfo; 22 import android.content.pm.Signature; 23 24 import com.android.managedprovisioning.common.ProvisionLogger; 25 import com.android.managedprovisioning.common.StoreUtils; 26 import com.android.managedprovisioning.common.Utils; 27 import com.android.managedprovisioning.model.PackageDownloadInfo; 28 29 import java.util.Arrays; 30 import java.util.LinkedList; 31 import java.util.List; 32 33 /** 34 * Utils related to checksum calculations and comparison. 35 */ 36 final class ChecksumUtils { 37 38 private final Utils mUtils; 39 ChecksumUtils(Utils utils)40 ChecksumUtils(Utils utils) { 41 mUtils = requireNonNull(utils); 42 } 43 44 /** 45 * Returns whether a signature hash of downloaded apk matches the hash given in constructor. 46 */ doesASignatureHashMatch(PackageInfo packageInfo, byte[] signatureChecksum)47 boolean doesASignatureHashMatch(PackageInfo packageInfo, byte[] signatureChecksum) { 48 ProvisionLogger.logd("Checking " + Utils.SHA256_TYPE 49 + "-hashes of all signatures of downloaded package."); 50 List<byte[]> sigHashes = computeHashesOfAllSignatures(packageInfo.signatures); 51 if (sigHashes == null || sigHashes.isEmpty()) { 52 ProvisionLogger.loge("Downloaded package does not have any signatures."); 53 return false; 54 } 55 56 for (byte[] sigHash : sigHashes) { 57 if (Arrays.equals(sigHash, signatureChecksum)) { 58 return true; 59 } 60 } 61 62 ProvisionLogger.loge("Provided hash does not match any signature hash."); 63 ProvisionLogger.loge("Hash provided by programmer: " 64 + StoreUtils.byteArrayToString(signatureChecksum)); 65 ProvisionLogger.loge("Hashes computed from package signatures: "); 66 for (byte[] sigHash : sigHashes) { 67 if (sigHash != null) { 68 ProvisionLogger.loge(StoreUtils.byteArrayToString(sigHash)); 69 } 70 } 71 72 return false; 73 } 74 75 /** 76 * Returns whether the package hash of downloaded file matches the hash given in {@link 77 * PackageDownloadInfo}. By default, {@code SHA-256} is used to verify the file hash. 78 */ doesPackageHashMatch(String downloadLocation, byte[] packageChecksum)79 boolean doesPackageHashMatch(String downloadLocation, byte[] packageChecksum) { 80 byte[] packageSha256Hash = null; 81 82 ProvisionLogger.logd("Checking file hash of entire apk file."); 83 packageSha256Hash = mUtils.computeHashOfFile(downloadLocation, Utils.SHA256_TYPE); 84 if (Arrays.equals(packageChecksum, packageSha256Hash)) { 85 return true; 86 } 87 88 ProvisionLogger.loge("Provided hash does not match file hash."); 89 ProvisionLogger.loge("Hash provided by programmer: " 90 + StoreUtils.byteArrayToString(packageChecksum)); 91 if (packageSha256Hash != null) { 92 ProvisionLogger.loge("SHA-256 Hash computed from file: " 93 + StoreUtils.byteArrayToString(packageSha256Hash)); 94 } 95 return false; 96 } 97 computeHashesOfAllSignatures(Signature[] signatures)98 private List<byte[]> computeHashesOfAllSignatures(Signature[] signatures) { 99 if (signatures == null) { 100 return null; 101 } 102 103 List<byte[]> hashes = new LinkedList<>(); 104 for (Signature signature : signatures) { 105 byte[] hash = mUtils.computeHashOfByteArray(signature.toByteArray()); 106 hashes.add(hash); 107 } 108 return hashes; 109 } 110 } 111