Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 63d2491b authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Create utils class to standardize implementation on hex digest of bytes."

parents c9b6967e 068e09a1
Loading
Loading
Loading
Loading
+4 −11
Original line number Diff line number Diff line
@@ -25,6 +25,8 @@ import static android.content.integrity.AppIntegrityManager.STATUS_FAILURE;
import static android.content.integrity.AppIntegrityManager.STATUS_SUCCESS;
import static android.content.pm.PackageManager.EXTRA_VERIFICATION_ID;

import static com.android.server.integrity.IntegrityUtils.getHexDigest;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.BroadcastReceiver;
@@ -331,7 +333,7 @@ public class AppIntegrityManagerServiceImpl extends IAppIntegrityManager.Stub {
        try {
            MessageDigest messageDigest = MessageDigest.getInstance("SHA-256");
            byte[] hashBytes = messageDigest.digest(packageName.getBytes(StandardCharsets.UTF_8));
            return toHexString(hashBytes);
            return getHexDigest(hashBytes);
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException("SHA-256 algorithm not found", e);
        }
@@ -425,21 +427,12 @@ public class AppIntegrityManagerServiceImpl extends IAppIntegrityManager.Stub {
        try {
            MessageDigest digest = MessageDigest.getInstance("SHA-256");
            byte[] publicKey = digest.digest(certificate.getEncoded());
            return toHexString(publicKey);
            return getHexDigest(publicKey);
        } catch (NoSuchAlgorithmException | CertificateEncodingException e) {
            throw new IllegalArgumentException("Error error computing fingerprint", e);
        }
    }

    private static String toHexString(byte[] bytes) {
        // each byte is represented by two hex chars
        StringBuffer hexString = new StringBuffer(bytes.length * 2);
        for (int i = 0; i < bytes.length; i++) {
            hexString.append(String.format("%02X", bytes[i]));
        }
        return new String(hexString);
    }

    private PackageInfo getPackageArchiveInfo(Uri dataUri) {
        File installationPath = getInstallationPath(dataUri);
        if (installationPath == null) {
+79 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2019 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.server.integrity;

import static com.android.internal.util.Preconditions.checkArgument;

/** Utils class for simple operations used in integrity module. */
public class IntegrityUtils {

    private static final char[] HEX_CHARS = "0123456789ABCDEF".toCharArray();

    /**
     * Obtain the raw bytes from hex encoded string.
     *
     * @throws IllegalArgumentException if {@code hexDigest} is not a valid hex encoding of some
     *     bytes
     */
    public static byte[] getBytesFromHexDigest(String hexDigest) {
        checkArgument(
                hexDigest.length() % 2 == 0,
                "Invalid hex encoding " + hexDigest + ": must have even length");

        byte[] rawBytes = new byte[hexDigest.length() / 2];
        for (int i = 0; i < rawBytes.length; i++) {
            int upperNibble = hexDigest.charAt(2 * i);
            int lowerNibble = hexDigest.charAt(2 * i + 1);
            rawBytes[i] = (byte) ((hexToDec(upperNibble) << 4) | hexToDec(lowerNibble));
        }
        return rawBytes;
    }

    /** Obtain hex encoded string from raw bytes. */
    public static String getHexDigest(byte[] rawBytes) {
        char[] hexChars = new char[rawBytes.length * 2];

        for (int i = 0; i < rawBytes.length; i++) {
            int upperNibble = (rawBytes[i] >>> 4) & 0xF;
            int lowerNibble = rawBytes[i] & 0xF;
            hexChars[i * 2] = decToHex(upperNibble);
            hexChars[i * 2 + 1] = decToHex(lowerNibble);
        }
        return new String(hexChars);
    }

    private static int hexToDec(int hexChar) {
        if (hexChar >= '0' && hexChar <= '9') {
            return hexChar - '0';
        }
        if (hexChar >= 'a' && hexChar <= 'f') {
            return hexChar - 'a' + 10;
        }
        if (hexChar >= 'A' && hexChar <= 'F') {
            return hexChar - 'A' + 10;
        }
        throw new IllegalArgumentException("Invalid hex char " + hexChar);
    }

    private static char decToHex(int dec) {
        if (dec >= 0 && dec < HEX_CHARS.length) {
            return HEX_CHARS[dec];
        }

        throw new IllegalArgumentException("Invalid dec value to be converted to hex digit " + dec);
    }
}
+61 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2019 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.server.integrity;

import static com.android.server.integrity.IntegrityUtils.getBytesFromHexDigest;
import static com.android.server.integrity.IntegrityUtils.getHexDigest;
import static com.android.server.testutils.TestUtils.assertExpectException;

import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;

import androidx.test.runner.AndroidJUnit4;

import org.junit.Test;
import org.junit.runner.RunWith;

/** Unit test for {@link com.android.server.integrity.IntegrityUtils} */
@RunWith(AndroidJUnit4.class)
public class IntegrityUtilsTest {

    private static final String HEX_DIGEST = "1234567890ABCDEF";
    private static final byte[] BYTES =
            new byte[] {0x12, 0x34, 0x56, 0x78, (byte) 0x90, (byte) 0xAB, (byte) 0xCD, (byte) 0xEF};

    @Test
    public void testGetBytesFromHexDigest() {
        assertArrayEquals(BYTES, getBytesFromHexDigest(HEX_DIGEST));
    }

    @Test
    public void testGetHexDigest() {
        assertEquals(HEX_DIGEST, getHexDigest(BYTES));
    }

    @Test
    public void testInvalidHexDigest() {
        assertExpectException(
                IllegalArgumentException.class,
                "must have even length",
                () -> getBytesFromHexDigest("ABC"));

        assertExpectException(
                IllegalArgumentException.class,
                "Invalid hex char",
                () -> getBytesFromHexDigest("GH"));
    }
}