Loading services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java +4 −11 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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); } Loading Loading @@ -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) { Loading services/core/java/com/android/server/integrity/IntegrityUtils.java 0 → 100644 +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); } } services/tests/servicestests/src/com/android/server/integrity/IntegrityUtilsTest.java 0 → 100644 +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")); } } Loading
services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java +4 −11 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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); } Loading Loading @@ -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) { Loading
services/core/java/com/android/server/integrity/IntegrityUtils.java 0 → 100644 +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); } }
services/tests/servicestests/src/com/android/server/integrity/IntegrityUtilsTest.java 0 → 100644 +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")); } }