/* * Copyright (C) 2022 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 com.android.managedprovisioning.task; import static java.util.Objects.requireNonNull; import android.content.pm.PackageInfo; import android.content.pm.Signature; import com.android.managedprovisioning.common.ProvisionLogger; import com.android.managedprovisioning.common.StoreUtils; import com.android.managedprovisioning.common.Utils; import com.android.managedprovisioning.model.PackageDownloadInfo; import java.util.Arrays; import java.util.LinkedList; import java.util.List; /** * Utils related to checksum calculations and comparison. */ final class ChecksumUtils { private final Utils mUtils; ChecksumUtils(Utils utils) { mUtils = requireNonNull(utils); } /** * Returns whether a signature hash of downloaded apk matches the hash given in constructor. */ boolean doesASignatureHashMatch(PackageInfo packageInfo, byte[] signatureChecksum) { ProvisionLogger.logd("Checking " + Utils.SHA256_TYPE + "-hashes of all signatures of downloaded package."); List sigHashes = computeHashesOfAllSignatures(packageInfo.signatures); if (sigHashes == null || sigHashes.isEmpty()) { ProvisionLogger.loge("Downloaded package does not have any signatures."); return false; } for (byte[] sigHash : sigHashes) { if (Arrays.equals(sigHash, signatureChecksum)) { return true; } } ProvisionLogger.loge("Provided hash does not match any signature hash."); ProvisionLogger.loge("Hash provided by programmer: " + StoreUtils.byteArrayToString(signatureChecksum)); ProvisionLogger.loge("Hashes computed from package signatures: "); for (byte[] sigHash : sigHashes) { if (sigHash != null) { ProvisionLogger.loge(StoreUtils.byteArrayToString(sigHash)); } } return false; } /** * Returns whether the package hash of downloaded file matches the hash given in {@link * PackageDownloadInfo}. By default, {@code SHA-256} is used to verify the file hash. */ boolean doesPackageHashMatch(String downloadLocation, byte[] packageChecksum) { byte[] packageSha256Hash = null; ProvisionLogger.logd("Checking file hash of entire apk file."); packageSha256Hash = mUtils.computeHashOfFile(downloadLocation, Utils.SHA256_TYPE); if (Arrays.equals(packageChecksum, packageSha256Hash)) { return true; } ProvisionLogger.loge("Provided hash does not match file hash."); ProvisionLogger.loge("Hash provided by programmer: " + StoreUtils.byteArrayToString(packageChecksum)); if (packageSha256Hash != null) { ProvisionLogger.loge("SHA-256 Hash computed from file: " + StoreUtils.byteArrayToString(packageSha256Hash)); } return false; } private List computeHashesOfAllSignatures(Signature[] signatures) { if (signatures == null) { return null; } List hashes = new LinkedList<>(); for (Signature signature : signatures) { byte[] hash = mUtils.computeHashOfByteArray(signature.toByteArray()); hashes.add(hash); } return hashes; } }