Merge "Resolve Android security comments for Android ID migration."
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -80,6 +80,6 @@ public final class PackageUtils {
|
||||
|
||||
messageDigest.update(data);
|
||||
|
||||
return ByteStringUtils.toString(messageDigest.digest());
|
||||
return ByteStringUtils.toHexString(messageDigest.digest());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user