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

Commit 8bd8564a authored by Mark Rathjen's avatar Mark Rathjen Committed by Android (Google) Code Review
Browse files

Merge "Resolve Android security comments for Android ID migration."

parents a92c1801 7599f136
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -33,7 +33,7 @@ public final class ByteStringUtils {
   * @param bytes Byte array to encode.
   * @return Hex encoded string representation of bytes.
   */
  public static String toString(byte[] bytes) {
  public static String toHexString(byte[] bytes) {
    if (bytes == null || bytes.length == 0 || bytes.length % 2 != 0) {
      return null;
    }
@@ -55,7 +55,7 @@ public final class ByteStringUtils {
   * @param str Hex encoded string to decode.
   * @return Decoded byte array representation of str.
   */
  public static byte[] toByteArray(String str) {
  public static byte[] fromHexToByteArray(String str) {
    if (str == null || str.length() == 0 || str.length() % 2 != 0) {
      return null;
    }
+1 −1
Original line number Diff line number Diff line
@@ -80,6 +80,6 @@ public final class PackageUtils {

        messageDigest.update(data);

        return ByteStringUtils.toString(messageDigest.digest());
        return ByteStringUtils.toHexString(messageDigest.digest());
    }
}
+36 −16
Original line number Diff line number Diff line
@@ -80,16 +80,20 @@ import java.io.FileDescriptor;
import java.io.FileNotFoundException;
import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.nio.ByteBuffer;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

import static android.os.Process.ROOT_UID;
import static android.os.Process.SHELL_UID;
@@ -996,7 +1000,7 @@ public class SettingsProvider extends ContentProvider {
                    continue;
                }

                // As of Android O (API 24), the SSAID is read from an app-specific entry in table
                // As of Android O, the SSAID is read from an app-specific entry in table
                // SETTINGS_FILE_SSAID, unless accessed by a system process.
                final Setting setting;
                if (isNewSsaidSetting(name)) {
@@ -1035,7 +1039,7 @@ public class SettingsProvider extends ContentProvider {

        // Get the value.
        synchronized (mLock) {
            // As of Android O (API 24), the SSAID is read from an app-specific entry in table
            // As of Android O, the SSAID is read from an app-specific entry in table
            // SETTINGS_FILE_SSAID, unless accessed by a system process.
            if (isNewSsaidSetting(name)) {
                return getSsaidSettingLocked(owningUserId);
@@ -1978,12 +1982,12 @@ public class SettingsProvider extends ContentProvider {

        private void generateUserKeyLocked(int userId) {
            // Generate a random key for each user used for creating a new ssaid.
            final byte[] keyBytes = new byte[16];
            final byte[] keyBytes = new byte[32];
            final SecureRandom rand = new SecureRandom();
            rand.nextBytes(keyBytes);

            // Convert to string for storage in settings table.
            final String userKey = ByteStringUtils.toString(keyBytes);
            final String userKey = ByteStringUtils.toHexString(keyBytes);

            // Store the key in the ssaid table.
            final SettingsState ssaidSettings = getSettingsLocked(SETTINGS_TYPE_SSAID, userId);
@@ -1995,6 +1999,10 @@ public class SettingsProvider extends ContentProvider {
            }
        }

        private byte[] getLengthPrefix(byte[] data) {
            return ByteBuffer.allocate(4).putInt(data.length).array();
        }

        public Setting generateSsaidLocked(String packageName, int userId) {
            final PackageInfo packageInfo;
            try {
@@ -2019,25 +2027,37 @@ public class SettingsProvider extends ContentProvider {
            final String userKey = userKeySetting.getValue();

            // Convert the user's key back to a byte array.
            final byte[] keyBytes = ByteStringUtils.toByteArray(userKey);
            if (keyBytes == null || keyBytes.length != 16) {
            final byte[] keyBytes = ByteStringUtils.fromHexToByteArray(userKey);

            // Validate that the key is of expected length.
            // Keys are currently 32 bytes, but were once 16 bytes during Android O development.
            if (keyBytes == null || (keyBytes.length != 16 && keyBytes.length != 32)) {
                throw new IllegalStateException("User key invalid");
            }

            final MessageDigest md;
            final Mac m;
            try {
                // Hash package name and signature.
                md = MessageDigest.getInstance("SHA-256");
                m = Mac.getInstance("HmacSHA256");
                m.init(new SecretKeySpec(keyBytes, m.getAlgorithm()));
            } catch (NoSuchAlgorithmException e) {
                throw new IllegalStateException("HmacSHA256 is not available");
                throw new IllegalStateException("HmacSHA256 is not available", e);
            } catch (InvalidKeyException e) {
                throw new IllegalStateException("Key is corrupted", e);
            }

            // Mac the package name and each of the signatures.
            byte[] packageNameBytes = packageInfo.packageName.getBytes(StandardCharsets.UTF_8);
            m.update(getLengthPrefix(packageNameBytes), 0, 4);
            m.update(packageNameBytes);
            for (int i = 0; i < packageInfo.signatures.length; i++) {
                byte[] sig = packageInfo.signatures[i].toByteArray();
                m.update(getLengthPrefix(sig), 0, 4);
                m.update(sig);
            }
            md.update(keyBytes);
            md.update(packageInfo.packageName.getBytes(StandardCharsets.UTF_8));
            md.update(packageInfo.signatures[0].toByteArray());

            // Convert result to a string for storage in settings table. Only want first 64 bits.
            final String ssaid = ByteStringUtils.toString(md.digest()).substring(0, 16)
                    .toLowerCase();
            final String ssaid = ByteStringUtils.toHexString(m.doFinal()).substring(0, 16)
                    .toLowerCase(Locale.US);

            // Save the ssaid in the ssaid table.
            final String uid = Integer.toString(packageInfo.applicationInfo.uid);