DO NOT MERGE Refactor passwords/pins/patterns to byte[]
Relating to frameworks/base
Bug: 120484642
Test: manual - test setting and unlocking passwords/pins/patterns.
automated - atest services/tests/servicestests/src/com/android/server/locksettings/
Change-Id: I57aa530ca2db1a026c56b66f5b4c91172f2667f6
(cherry picked from commit f64ec63a02)
This commit is contained in:
@@ -107,7 +107,10 @@ public class PasswordMetrics implements Parcelable {
|
||||
}
|
||||
};
|
||||
|
||||
public static PasswordMetrics computeForPassword(@NonNull String password) {
|
||||
/**
|
||||
* Returns the {@code PasswordMetrics} for a given password
|
||||
*/
|
||||
public static PasswordMetrics computeForPassword(@NonNull byte[] password) {
|
||||
// Analyse the characters used
|
||||
int letters = 0;
|
||||
int upperCase = 0;
|
||||
@@ -115,9 +118,9 @@ public class PasswordMetrics implements Parcelable {
|
||||
int numeric = 0;
|
||||
int symbols = 0;
|
||||
int nonLetter = 0;
|
||||
final int length = password.length();
|
||||
final int length = password.length;
|
||||
for (int i = 0; i < length; i++) {
|
||||
switch (categoryChar(password.charAt(i))) {
|
||||
switch (categoryChar((char) password[i])) {
|
||||
case CHAR_LOWER_CASE:
|
||||
letters++;
|
||||
lowerCase++;
|
||||
@@ -173,7 +176,7 @@ public class PasswordMetrics implements Parcelable {
|
||||
&& this.nonLetter == o.nonLetter;
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* Returns the maximum length of a sequential characters. A sequence is defined as
|
||||
* monotonically increasing characters with a constant interval or the same character repeated.
|
||||
*
|
||||
@@ -187,19 +190,19 @@ public class PasswordMetrics implements Parcelable {
|
||||
* maxLengthSequence(";;;;") == 4 (anything that repeats)
|
||||
* maxLengthSequence(":;<=>") == 1 (ordered, but not composed of alphas or digits)
|
||||
*
|
||||
* @param string the pass
|
||||
* @param bytes the pass
|
||||
* @return the number of sequential letters or digits
|
||||
*/
|
||||
public static int maxLengthSequence(@NonNull String string) {
|
||||
if (string.length() == 0) return 0;
|
||||
char previousChar = string.charAt(0);
|
||||
public static int maxLengthSequence(@NonNull byte[] bytes) {
|
||||
if (bytes.length == 0) return 0;
|
||||
char previousChar = (char) bytes[0];
|
||||
@CharacterCatagory int category = categoryChar(previousChar); //current sequence category
|
||||
int diff = 0; //difference between two consecutive characters
|
||||
boolean hasDiff = false; //if we are currently targeting a sequence
|
||||
int maxLength = 0; //maximum length of a sequence already found
|
||||
int startSequence = 0; //where the current sequence started
|
||||
for (int current = 1; current < string.length(); current++) {
|
||||
char currentChar = string.charAt(current);
|
||||
for (int current = 1; current < bytes.length; current++) {
|
||||
char currentChar = (char) bytes[current];
|
||||
@CharacterCatagory int categoryCurrent = categoryChar(currentChar);
|
||||
int currentDiff = (int) currentChar - (int) previousChar;
|
||||
if (categoryCurrent != category || Math.abs(currentDiff) > maxDiffCategory(category)) {
|
||||
@@ -218,7 +221,7 @@ public class PasswordMetrics implements Parcelable {
|
||||
}
|
||||
previousChar = currentChar;
|
||||
}
|
||||
maxLength = Math.max(maxLength, string.length() - startSequence);
|
||||
maxLength = Math.max(maxLength, bytes.length - startSequence);
|
||||
return maxLength;
|
||||
}
|
||||
|
||||
|
||||
@@ -36,17 +36,17 @@ interface ILockSettings {
|
||||
boolean getBoolean(in String key, in boolean defaultValue, in int userId);
|
||||
long getLong(in String key, in long defaultValue, in int userId);
|
||||
String getString(in String key, in String defaultValue, in int userId);
|
||||
void setLockCredential(in String credential, int type, in String savedCredential, int requestedQuality, int userId);
|
||||
void setLockCredential(in byte[] credential, int type, in byte[] savedCredential, int requestedQuality, int userId);
|
||||
void resetKeyStore(int userId);
|
||||
VerifyCredentialResponse checkCredential(in String credential, int type, int userId,
|
||||
VerifyCredentialResponse checkCredential(in byte[] credential, int type, int userId,
|
||||
in ICheckCredentialProgressCallback progressCallback);
|
||||
VerifyCredentialResponse verifyCredential(in String credential, int type, long challenge, int userId);
|
||||
VerifyCredentialResponse verifyTiedProfileChallenge(String credential, int type, long challenge, int userId);
|
||||
VerifyCredentialResponse verifyCredential(in byte[] credential, int type, long challenge, int userId);
|
||||
VerifyCredentialResponse verifyTiedProfileChallenge(in byte[] credential, int type, long challenge, int userId);
|
||||
boolean checkVoldPassword(int userId);
|
||||
boolean havePattern(int userId);
|
||||
boolean havePassword(int userId);
|
||||
byte[] getHashFactor(String currentCredential, int userId);
|
||||
void setSeparateProfileChallengeEnabled(int userId, boolean enabled, String managedUserPassword);
|
||||
byte[] getHashFactor(in byte[] currentCredential, int userId);
|
||||
void setSeparateProfileChallengeEnabled(int userId, boolean enabled, in byte[] managedUserPassword);
|
||||
boolean getSeparateProfileChallengeEnabled(int userId);
|
||||
void registerStrongAuthTracker(in IStrongAuthTracker tracker);
|
||||
void unregisterStrongAuthTracker(in IStrongAuthTracker tracker);
|
||||
|
||||
@@ -150,12 +150,33 @@ public final class LockPatternChecker {
|
||||
* @param challenge The challenge to verify against the pattern.
|
||||
* @param userId The user to check against the pattern.
|
||||
* @param callback The callback to be invoked with the verification result.
|
||||
*
|
||||
* @deprecated Pass the password as a byte array.
|
||||
*/
|
||||
@Deprecated
|
||||
public static AsyncTask<?, ?, ?> verifyPassword(final LockPatternUtils utils,
|
||||
final String password,
|
||||
final long challenge,
|
||||
final int userId,
|
||||
final OnVerifyCallback callback) {
|
||||
byte[] passwordBytes = password != null ? password.getBytes() : null;
|
||||
return verifyPassword(utils, passwordBytes, challenge, userId, callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify a password asynchronously.
|
||||
*
|
||||
* @param utils The LockPatternUtils instance to use.
|
||||
* @param password The password to check.
|
||||
* @param challenge The challenge to verify against the pattern.
|
||||
* @param userId The user to check against the pattern.
|
||||
* @param callback The callback to be invoked with the verification result.
|
||||
*/
|
||||
public static AsyncTask<?, ?, ?> verifyPassword(final LockPatternUtils utils,
|
||||
final byte[] password,
|
||||
final long challenge,
|
||||
final int userId,
|
||||
final OnVerifyCallback callback) {
|
||||
AsyncTask<Void, Void, byte[]> task = new AsyncTask<Void, Void, byte[]>() {
|
||||
private int mThrottleTimeout;
|
||||
|
||||
@@ -188,7 +209,7 @@ public final class LockPatternChecker {
|
||||
* @param callback The callback to be invoked with the verification result.
|
||||
*/
|
||||
public static AsyncTask<?, ?, ?> verifyTiedProfileChallenge(final LockPatternUtils utils,
|
||||
final String password,
|
||||
final byte[] password,
|
||||
final boolean isPattern,
|
||||
final long challenge,
|
||||
final int userId,
|
||||
@@ -222,18 +243,36 @@ public final class LockPatternChecker {
|
||||
* @param password The password to check.
|
||||
* @param userId The user to check against the pattern.
|
||||
* @param callback The callback to be invoked with the check result.
|
||||
* @deprecated Pass passwords as byte[]
|
||||
*/
|
||||
@Deprecated
|
||||
public static AsyncTask<?, ?, ?> checkPassword(final LockPatternUtils utils,
|
||||
final String password,
|
||||
final int userId,
|
||||
final OnCheckCallback callback) {
|
||||
byte[] passwordBytes = password != null ? password.getBytes() : null;
|
||||
return checkPassword(utils, passwordBytes, userId, callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks a password asynchronously.
|
||||
*
|
||||
* @param utils The LockPatternUtils instance to use.
|
||||
* @param passwordBytes The password to check.
|
||||
* @param userId The user to check against the pattern.
|
||||
* @param callback The callback to be invoked with the check result.
|
||||
*/
|
||||
public static AsyncTask<?, ?, ?> checkPassword(final LockPatternUtils utils,
|
||||
final byte[] passwordBytes,
|
||||
final int userId,
|
||||
final OnCheckCallback callback) {
|
||||
AsyncTask<Void, Void, Boolean> task = new AsyncTask<Void, Void, Boolean>() {
|
||||
private int mThrottleTimeout;
|
||||
|
||||
@Override
|
||||
protected Boolean doInBackground(Void... args) {
|
||||
try {
|
||||
return utils.checkPassword(password, userId, callback::onEarlyMatched);
|
||||
return utils.checkPassword(passwordBytes, userId, callback::onEarlyMatched);
|
||||
} catch (RequestThrottledException ex) {
|
||||
mThrottleTimeout = ex.getTimeoutMs();
|
||||
return false;
|
||||
|
||||
@@ -350,7 +350,7 @@ public class LockPatternUtils {
|
||||
null /* componentName */, userId);
|
||||
}
|
||||
|
||||
private byte[] verifyCredential(String credential, int type, long challenge, int userId)
|
||||
private byte[] verifyCredential(byte[] credential, int type, long challenge, int userId)
|
||||
throws RequestThrottledException {
|
||||
try {
|
||||
VerifyCredentialResponse response = getLockSettings().verifyCredential(credential,
|
||||
@@ -367,7 +367,7 @@ public class LockPatternUtils {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean checkCredential(String credential, int type, int userId,
|
||||
private boolean checkCredential(byte[] credential, int type, int userId,
|
||||
@Nullable CheckCredentialProgressCallback progressCallback)
|
||||
throws RequestThrottledException {
|
||||
try {
|
||||
@@ -398,7 +398,7 @@ public class LockPatternUtils {
|
||||
public byte[] verifyPattern(List<LockPatternView.Cell> pattern, long challenge, int userId)
|
||||
throws RequestThrottledException {
|
||||
throwIfCalledOnMainThread();
|
||||
return verifyCredential(patternToString(pattern), CREDENTIAL_TYPE_PATTERN, challenge,
|
||||
return verifyCredential(patternToByteArray(pattern), CREDENTIAL_TYPE_PATTERN, challenge,
|
||||
userId);
|
||||
}
|
||||
|
||||
@@ -423,7 +423,7 @@ public class LockPatternUtils {
|
||||
@Nullable CheckCredentialProgressCallback progressCallback)
|
||||
throws RequestThrottledException {
|
||||
throwIfCalledOnMainThread();
|
||||
return checkCredential(patternToString(pattern), CREDENTIAL_TYPE_PATTERN, userId,
|
||||
return checkCredential(patternToByteArray(pattern), CREDENTIAL_TYPE_PATTERN, userId,
|
||||
progressCallback);
|
||||
}
|
||||
|
||||
@@ -436,7 +436,7 @@ public class LockPatternUtils {
|
||||
* @param challenge The challenge to verify against the password
|
||||
* @return the attestation that the challenge was verified, or null.
|
||||
*/
|
||||
public byte[] verifyPassword(String password, long challenge, int userId)
|
||||
public byte[] verifyPassword(byte[] password, long challenge, int userId)
|
||||
throws RequestThrottledException {
|
||||
throwIfCalledOnMainThread();
|
||||
return verifyCredential(password, CREDENTIAL_TYPE_PASSWORD, challenge, userId);
|
||||
@@ -452,7 +452,7 @@ public class LockPatternUtils {
|
||||
* @param challenge The challenge to verify against the password
|
||||
* @return the attestation that the challenge was verified, or null.
|
||||
*/
|
||||
public byte[] verifyTiedProfileChallenge(String password, boolean isPattern, long challenge,
|
||||
public byte[] verifyTiedProfileChallenge(byte[] password, boolean isPattern, long challenge,
|
||||
int userId) throws RequestThrottledException {
|
||||
throwIfCalledOnMainThread();
|
||||
try {
|
||||
@@ -474,22 +474,53 @@ public class LockPatternUtils {
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Check to see if a password matches the saved password. If no password exists,
|
||||
* always returns true.
|
||||
* @param password The password to check.
|
||||
* @return Whether the password matches the stored one.
|
||||
*/
|
||||
public boolean checkPassword(String password, int userId) throws RequestThrottledException {
|
||||
byte[] passwordBytes = password != null ? password.getBytes() : null;
|
||||
return checkPassword(passwordBytes, userId, null /* progressCallback */);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* Check to see if a password matches the saved password. If no password exists,
|
||||
* always returns true.
|
||||
* @param password The password to check.
|
||||
* @return Whether the password matches the stored one.
|
||||
*/
|
||||
public boolean checkPassword(byte[] password, int userId) throws RequestThrottledException {
|
||||
return checkPassword(password, userId, null /* progressCallback */);
|
||||
}
|
||||
|
||||
// TODO(b/120484642): This method is necessary for vendor/qcom code and is a hidden api
|
||||
/* *
|
||||
* Check to see if a password matches the saved password. If no password exists,
|
||||
* always returns true.
|
||||
* @param password The password to check.
|
||||
* @return Whether the password matches the stored one.
|
||||
*/
|
||||
public boolean checkPassword(String password, int userId,
|
||||
@Nullable CheckCredentialProgressCallback progressCallback)
|
||||
throws RequestThrottledException {
|
||||
byte[] passwordBytes = password != null ? password.getBytes() : null;
|
||||
throwIfCalledOnMainThread();
|
||||
return checkCredential(passwordBytes, CREDENTIAL_TYPE_PASSWORD, userId, progressCallback);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Check to see if a password matches the saved password. If no password exists,
|
||||
* always returns true.
|
||||
* @param password The password to check.
|
||||
* @return Whether the password matches the stored one.
|
||||
*/
|
||||
public boolean checkPassword(String password, int userId,
|
||||
|
||||
public boolean checkPassword(byte[] password, int userId,
|
||||
@Nullable CheckCredentialProgressCallback progressCallback)
|
||||
throws RequestThrottledException {
|
||||
throwIfCalledOnMainThread();
|
||||
@@ -513,7 +544,7 @@ public class LockPatternUtils {
|
||||
* Returns the password history hash factor, needed to check new password against password
|
||||
* history with {@link #checkPasswordHistory(String, byte[], int)}
|
||||
*/
|
||||
public byte[] getPasswordHistoryHashFactor(String currentPassword, int userId) {
|
||||
public byte[] getPasswordHistoryHashFactor(byte[] currentPassword, int userId) {
|
||||
try {
|
||||
return getLockSettings().getHashFactor(currentPassword, userId);
|
||||
} catch (RemoteException e) {
|
||||
@@ -531,8 +562,8 @@ public class LockPatternUtils {
|
||||
* {@link ILockSettings#getHashFactor}
|
||||
* @return Whether the password matches any in the history.
|
||||
*/
|
||||
public boolean checkPasswordHistory(String passwordToCheck, byte[] hashFactor, int userId) {
|
||||
if (TextUtils.isEmpty(passwordToCheck)) {
|
||||
public boolean checkPasswordHistory(byte[] passwordToCheck, byte[] hashFactor, int userId) {
|
||||
if (passwordToCheck == null || passwordToCheck.length == 0) {
|
||||
Log.e(TAG, "checkPasswordHistory: empty password");
|
||||
return false;
|
||||
}
|
||||
@@ -633,13 +664,13 @@ public class LockPatternUtils {
|
||||
/**
|
||||
* Clear any lock pattern or password.
|
||||
*/
|
||||
public void clearLock(String savedCredential, int userHandle) {
|
||||
public void clearLock(byte[] savedCredential, int userHandle) {
|
||||
final int currentQuality = getKeyguardStoredPasswordQuality(userHandle);
|
||||
setKeyguardStoredPasswordQuality(PASSWORD_QUALITY_UNSPECIFIED, userHandle);
|
||||
|
||||
try{
|
||||
getLockSettings().setLockCredential(null, CREDENTIAL_TYPE_NONE, savedCredential,
|
||||
PASSWORD_QUALITY_UNSPECIFIED, userHandle);
|
||||
getLockSettings().setLockCredential(null, CREDENTIAL_TYPE_NONE,
|
||||
savedCredential, PASSWORD_QUALITY_UNSPECIFIED, userHandle);
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Failed to clear lock", e);
|
||||
setKeyguardStoredPasswordQuality(currentQuality, userHandle);
|
||||
@@ -698,21 +729,22 @@ public class LockPatternUtils {
|
||||
/**
|
||||
* Save a lock pattern.
|
||||
* @param pattern The new pattern to save.
|
||||
* @param savedPattern The previously saved pattern, converted to String format
|
||||
* @param savedPattern The previously saved pattern, converted to byte[] format
|
||||
* @param userId the user whose pattern is to be saved.
|
||||
*/
|
||||
public void saveLockPattern(List<LockPatternView.Cell> pattern, String savedPattern, int userId) {
|
||||
public void saveLockPattern(List<LockPatternView.Cell> pattern, byte[] savedPattern,
|
||||
int userId) {
|
||||
if (pattern == null || pattern.size() < MIN_LOCK_PATTERN_SIZE) {
|
||||
throw new IllegalArgumentException("pattern must not be null and at least "
|
||||
+ MIN_LOCK_PATTERN_SIZE + " dots long.");
|
||||
}
|
||||
|
||||
final String stringPattern = patternToString(pattern);
|
||||
final byte[] bytePattern = patternToByteArray(pattern);
|
||||
final int currentQuality = getKeyguardStoredPasswordQuality(userId);
|
||||
setKeyguardStoredPasswordQuality(PASSWORD_QUALITY_SOMETHING, userId);
|
||||
try {
|
||||
getLockSettings().setLockCredential(stringPattern, CREDENTIAL_TYPE_PATTERN,
|
||||
savedPattern, PASSWORD_QUALITY_SOMETHING, userId);
|
||||
getLockSettings().setLockCredential(bytePattern, CREDENTIAL_TYPE_PATTERN, savedPattern,
|
||||
PASSWORD_QUALITY_SOMETHING, userId);
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Couldn't save lock pattern", e);
|
||||
setKeyguardStoredPasswordQuality(currentQuality, userId);
|
||||
@@ -724,7 +756,7 @@ public class LockPatternUtils {
|
||||
if (!shouldEncryptWithCredentials(true)) {
|
||||
clearEncryptionPassword();
|
||||
} else {
|
||||
updateEncryptionPassword(StorageManager.CRYPT_TYPE_PATTERN, stringPattern);
|
||||
updateEncryptionPassword(StorageManager.CRYPT_TYPE_PATTERN, bytePattern);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -796,7 +828,7 @@ public class LockPatternUtils {
|
||||
}
|
||||
|
||||
/** Update the encryption password if it is enabled **/
|
||||
private void updateEncryptionPassword(final int type, final String password) {
|
||||
private void updateEncryptionPassword(final int type, final byte[] password) {
|
||||
if (!isDeviceEncryptionEnabled()) {
|
||||
return;
|
||||
}
|
||||
@@ -811,7 +843,9 @@ public class LockPatternUtils {
|
||||
protected Void doInBackground(Void... dummy) {
|
||||
IStorageManager storageManager = IStorageManager.Stub.asInterface(service);
|
||||
try {
|
||||
storageManager.changeEncryptionPassword(type, password);
|
||||
// TODO(b/120484642): This is a location where we still use a String for vold
|
||||
String passwordString = password != null ? new String(password) : null;
|
||||
storageManager.changeEncryptionPassword(type, passwordString);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Error changing encryption password", e);
|
||||
}
|
||||
@@ -828,10 +862,30 @@ public class LockPatternUtils {
|
||||
* @param savedPassword The previously saved lock password, or null if none
|
||||
* @param requestedQuality {@see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)}
|
||||
* @param userHandle The userId of the user to change the password for
|
||||
*
|
||||
* @deprecated Pass password as a byte array
|
||||
*/
|
||||
@Deprecated
|
||||
public void saveLockPassword(String password, String savedPassword, int requestedQuality,
|
||||
int userHandle) {
|
||||
if (password == null || password.length() < MIN_LOCK_PASSWORD_SIZE) {
|
||||
byte[] passwordBytes = password != null ? password.getBytes() : null;
|
||||
byte[] savedPasswordBytes = savedPassword != null ? savedPassword.getBytes() : null;
|
||||
saveLockPassword(passwordBytes, savedPasswordBytes, requestedQuality, userHandle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Save a lock password. Does not ensure that the password is as good
|
||||
* as the requested mode, but will adjust the mode to be as good as the
|
||||
* password.
|
||||
* @param password The password to save
|
||||
* @param savedPassword The previously saved lock password, or null if none
|
||||
* @param requestedQuality {@see DevicePolicyManager#getPasswordQuality(
|
||||
* android.content.ComponentName)}
|
||||
* @param userHandle The userId of the user to change the password for
|
||||
*/
|
||||
public void saveLockPassword(byte[] password, byte[] savedPassword, int requestedQuality,
|
||||
int userHandle) {
|
||||
if (password == null || password.length < MIN_LOCK_PASSWORD_SIZE) {
|
||||
throw new IllegalArgumentException("password must not be null and at least "
|
||||
+ "of length " + MIN_LOCK_PASSWORD_SIZE);
|
||||
}
|
||||
@@ -841,8 +895,8 @@ public class LockPatternUtils {
|
||||
computePasswordQuality(CREDENTIAL_TYPE_PASSWORD, password, requestedQuality),
|
||||
userHandle);
|
||||
try {
|
||||
getLockSettings().setLockCredential(password, CREDENTIAL_TYPE_PASSWORD,
|
||||
savedPassword, requestedQuality, userHandle);
|
||||
getLockSettings().setLockCredential(password, CREDENTIAL_TYPE_PASSWORD, savedPassword,
|
||||
requestedQuality, userHandle);
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Unable to save lock password", e);
|
||||
setKeyguardStoredPasswordQuality(currentQuality, userHandle);
|
||||
@@ -859,7 +913,7 @@ public class LockPatternUtils {
|
||||
* Update device encryption password if calling user is USER_SYSTEM and device supports
|
||||
* encryption.
|
||||
*/
|
||||
private void updateEncryptionPasswordIfNeeded(String password, int quality, int userHandle) {
|
||||
private void updateEncryptionPasswordIfNeeded(byte[] password, int quality, int userHandle) {
|
||||
// Update the device encryption password.
|
||||
if (userHandle == UserHandle.USER_SYSTEM
|
||||
&& LockPatternUtils.isDeviceEncryptionEnabled()) {
|
||||
@@ -879,8 +933,8 @@ public class LockPatternUtils {
|
||||
* Store the hash of the *current* password in the password history list, if device policy
|
||||
* enforces password history requirement.
|
||||
*/
|
||||
private void updatePasswordHistory(String password, int userHandle) {
|
||||
if (TextUtils.isEmpty(password)) {
|
||||
private void updatePasswordHistory(byte[] password, int userHandle) {
|
||||
if (password == null || password.length == 0) {
|
||||
Log.e(TAG, "checkPasswordHistory: empty password");
|
||||
return;
|
||||
}
|
||||
@@ -959,7 +1013,7 @@ public class LockPatternUtils {
|
||||
* if DevicePolicyManager has a stronger quality requirement. This value will be written
|
||||
* to PASSWORD_TYPE_KEY.
|
||||
*/
|
||||
private int computePasswordQuality(int type, String credential, int requestedQuality) {
|
||||
private int computePasswordQuality(int type, byte[] credential, int requestedQuality) {
|
||||
final int quality;
|
||||
if (type == CREDENTIAL_TYPE_PASSWORD) {
|
||||
int computedQuality = PasswordMetrics.computeForPassword(credential).quality;
|
||||
@@ -982,7 +1036,7 @@ public class LockPatternUtils {
|
||||
* true
|
||||
*/
|
||||
public void setSeparateProfileChallengeEnabled(int userHandle, boolean enabled,
|
||||
String managedUserPassword) {
|
||||
byte[] managedUserPassword) {
|
||||
if (!isManagedProfile(userHandle)) {
|
||||
return;
|
||||
}
|
||||
@@ -1046,15 +1100,28 @@ public class LockPatternUtils {
|
||||
* Deserialize a pattern.
|
||||
* @param string The pattern serialized with {@link #patternToString}
|
||||
* @return The pattern.
|
||||
* @deprecated Pass patterns as byte[] and use byteArrayToPattern
|
||||
*/
|
||||
@Deprecated
|
||||
public static List<LockPatternView.Cell> stringToPattern(String string) {
|
||||
if (string == null) {
|
||||
return null;
|
||||
}
|
||||
return byteArrayToPattern(string.getBytes());
|
||||
}
|
||||
|
||||
/**
|
||||
* Deserialize a pattern.
|
||||
* @param bytes The pattern serialized with {@link #patternToByteArray}
|
||||
* @return The pattern.
|
||||
*/
|
||||
public static List<LockPatternView.Cell> byteArrayToPattern(byte[] bytes) {
|
||||
if (bytes == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
List<LockPatternView.Cell> result = Lists.newArrayList();
|
||||
|
||||
final byte[] bytes = string.getBytes();
|
||||
for (int i = 0; i < bytes.length; i++) {
|
||||
byte b = (byte) (bytes[i] - '1');
|
||||
result.add(LockPatternView.Cell.of(b / 3, b % 3));
|
||||
@@ -1066,10 +1133,22 @@ public class LockPatternUtils {
|
||||
* Serialize a pattern.
|
||||
* @param pattern The pattern.
|
||||
* @return The pattern in string form.
|
||||
* @deprecated Use patternToByteArray instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public static String patternToString(List<LockPatternView.Cell> pattern) {
|
||||
return new String(patternToByteArray(pattern));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Serialize a pattern.
|
||||
* @param pattern The pattern.
|
||||
* @return The pattern in byte array form.
|
||||
*/
|
||||
public static byte[] patternToByteArray(List<LockPatternView.Cell> pattern) {
|
||||
if (pattern == null) {
|
||||
return "";
|
||||
return new byte[0];
|
||||
}
|
||||
final int patternSize = pattern.size();
|
||||
|
||||
@@ -1078,21 +1157,24 @@ public class LockPatternUtils {
|
||||
LockPatternView.Cell cell = pattern.get(i);
|
||||
res[i] = (byte) (cell.getRow() * 3 + cell.getColumn() + '1');
|
||||
}
|
||||
return new String(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
public static String patternStringToBaseZero(String pattern) {
|
||||
if (pattern == null) {
|
||||
return "";
|
||||
/**
|
||||
* Transform a pattern byte array to base zero form.
|
||||
* @param bytes pattern byte array.
|
||||
* @return The pattern in base zero form.
|
||||
*/
|
||||
public static byte[] patternByteArrayToBaseZero(byte[] bytes) {
|
||||
if (bytes == null) {
|
||||
return new byte[0];
|
||||
}
|
||||
final int patternSize = pattern.length();
|
||||
|
||||
final int patternSize = bytes.length;
|
||||
byte[] res = new byte[patternSize];
|
||||
final byte[] bytes = pattern.getBytes();
|
||||
for (int i = 0; i < patternSize; i++) {
|
||||
res[i] = (byte) (bytes[i] - '1');
|
||||
}
|
||||
return new String(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1146,13 +1228,18 @@ public class LockPatternUtils {
|
||||
*
|
||||
* @return the hash of the pattern in a byte array.
|
||||
*/
|
||||
public String legacyPasswordToHash(String password, int userId) {
|
||||
if (password == null) {
|
||||
public String legacyPasswordToHash(byte[] password, int userId) {
|
||||
if (password == null || password.length == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
byte[] saltedPassword = (password + getSalt(userId)).getBytes();
|
||||
// Previously the password was passed as a String with the following code:
|
||||
// byte[] saltedPassword = (password + getSalt(userId)).getBytes();
|
||||
// The code below creates the identical digest preimage using byte arrays:
|
||||
byte[] salt = getSalt(userId).getBytes();
|
||||
byte[] saltedPassword = Arrays.copyOf(password, password.length + salt.length);
|
||||
System.arraycopy(salt, 0, saltedPassword, password.length, salt.length);
|
||||
byte[] sha1 = MessageDigest.getInstance("SHA-1").digest(saltedPassword);
|
||||
byte[] md5 = MessageDigest.getInstance("MD5").digest(saltedPassword);
|
||||
|
||||
@@ -1161,6 +1248,7 @@ public class LockPatternUtils {
|
||||
System.arraycopy(md5, 0, combined, sha1.length, md5.length);
|
||||
|
||||
final char[] hexEncoded = HexEncoding.encode(combined);
|
||||
Arrays.fill(saltedPassword, (byte) 0);
|
||||
return new String(hexEncoded);
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new AssertionError("Missing digest algorithm: ", e);
|
||||
@@ -1170,14 +1258,19 @@ public class LockPatternUtils {
|
||||
/**
|
||||
* Hash the password for password history check purpose.
|
||||
*/
|
||||
private String passwordToHistoryHash(String passwordToHash, byte[] hashFactor, int userId) {
|
||||
if (TextUtils.isEmpty(passwordToHash) || hashFactor == null) {
|
||||
private String passwordToHistoryHash(byte[] passwordToHash, byte[] hashFactor, int userId) {
|
||||
if (passwordToHash == null || passwordToHash.length == 0 || hashFactor == null) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
MessageDigest sha256 = MessageDigest.getInstance("SHA-256");
|
||||
sha256.update(hashFactor);
|
||||
sha256.update((passwordToHash + getSalt(userId)).getBytes());
|
||||
byte[] salt = getSalt(userId).getBytes();
|
||||
byte[] saltedPassword = Arrays.copyOf(passwordToHash, passwordToHash.length
|
||||
+ salt.length);
|
||||
System.arraycopy(salt, 0, saltedPassword, passwordToHash.length, salt.length);
|
||||
sha256.update(saltedPassword);
|
||||
Arrays.fill(saltedPassword, (byte) 0);
|
||||
return new String(HexEncoding.encode(sha256.digest()));
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new AssertionError("Missing digest algorithm: ", e);
|
||||
@@ -1610,17 +1703,17 @@ public class LockPatternUtils {
|
||||
* @param userId The user who's lock credential to be changed
|
||||
* @return {@code true} if the operation is successful.
|
||||
*/
|
||||
public boolean setLockCredentialWithToken(String credential, int type, int requestedQuality,
|
||||
public boolean setLockCredentialWithToken(byte[] credential, int type, int requestedQuality,
|
||||
long tokenHandle, byte[] token, int userId) {
|
||||
LockSettingsInternal localService = getLockSettingsInternal();
|
||||
if (type != CREDENTIAL_TYPE_NONE) {
|
||||
if (TextUtils.isEmpty(credential) || credential.length() < MIN_LOCK_PASSWORD_SIZE) {
|
||||
if (credential == null || credential.length < MIN_LOCK_PASSWORD_SIZE) {
|
||||
throw new IllegalArgumentException("password must not be null and at least "
|
||||
+ "of length " + MIN_LOCK_PASSWORD_SIZE);
|
||||
}
|
||||
final int quality = computePasswordQuality(type, credential, requestedQuality);
|
||||
if (!localService.setLockCredentialWithToken(credential, type, tokenHandle,
|
||||
token, quality, userId)) {
|
||||
if (!localService.setLockCredentialWithToken(credential, type, tokenHandle, token,
|
||||
quality, userId)) {
|
||||
return false;
|
||||
}
|
||||
setKeyguardStoredPasswordQuality(quality, userId);
|
||||
@@ -1629,11 +1722,11 @@ public class LockPatternUtils {
|
||||
updatePasswordHistory(credential, userId);
|
||||
onAfterChangingPassword(userId);
|
||||
} else {
|
||||
if (!TextUtils.isEmpty(credential)) {
|
||||
if (!(credential == null || credential.length == 0)) {
|
||||
throw new IllegalArgumentException("password must be emtpy for NONE type");
|
||||
}
|
||||
if (!localService.setLockCredentialWithToken(null, CREDENTIAL_TYPE_NONE,
|
||||
tokenHandle, token, PASSWORD_QUALITY_UNSPECIFIED, userId)) {
|
||||
if (!localService.setLockCredentialWithToken(null, CREDENTIAL_TYPE_NONE, tokenHandle,
|
||||
token, PASSWORD_QUALITY_UNSPECIFIED, userId)) {
|
||||
return false;
|
||||
}
|
||||
setKeyguardStoredPasswordQuality(PASSWORD_QUALITY_UNSPECIFIED, userId);
|
||||
@@ -1854,4 +1947,22 @@ public class LockPatternUtils {
|
||||
return FRP_CREDENTIAL_ENABLED && context.getResources().getBoolean(
|
||||
com.android.internal.R.bool.config_enableCredentialFactoryResetProtection);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a CharSequence to a byte array without requiring a toString(), which creates an
|
||||
* additional copy.
|
||||
*
|
||||
* @param chars The CharSequence to convert
|
||||
* @return A byte array representing the input
|
||||
*/
|
||||
public static byte[] charSequenceToByteArray(CharSequence chars) {
|
||||
if (chars == null) {
|
||||
return null;
|
||||
}
|
||||
byte[] bytes = new byte[chars.length()];
|
||||
for (int i = 0; i < chars.length(); i++) {
|
||||
bytes[i] = (byte) chars.charAt(i);
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1274,8 +1274,10 @@ public class LockPatternView extends View {
|
||||
@Override
|
||||
protected Parcelable onSaveInstanceState() {
|
||||
Parcelable superState = super.onSaveInstanceState();
|
||||
byte[] patternBytes = LockPatternUtils.patternToByteArray(mPattern);
|
||||
String patternString = patternBytes != null ? new String(patternBytes) : null;
|
||||
return new SavedState(superState,
|
||||
LockPatternUtils.patternToString(mPattern),
|
||||
patternString,
|
||||
mPatternDisplayMode.ordinal(),
|
||||
mInputEnabled, mInStealthMode, mEnableHapticFeedback);
|
||||
}
|
||||
|
||||
@@ -49,7 +49,11 @@ public abstract class LockSettingsInternal {
|
||||
*/
|
||||
public abstract boolean isEscrowTokenActive(long handle, int userId);
|
||||
|
||||
public abstract boolean setLockCredentialWithToken(String credential, int type,
|
||||
/**
|
||||
* Set the lock credential.
|
||||
* @return true if password is set.
|
||||
*/
|
||||
public abstract boolean setLockCredentialWithToken(byte[] credential, int type,
|
||||
long tokenHandle, byte[] token, int requestedQuality, int userId);
|
||||
|
||||
public abstract boolean unlockUserWithToken(long tokenHandle, byte[] token, int userId);
|
||||
|
||||
@@ -80,7 +80,8 @@ public class PasswordMetricsTest {
|
||||
|
||||
@Test
|
||||
public void testComputeForPassword_metrics() {
|
||||
final PasswordMetrics metrics = PasswordMetrics.computeForPassword("6B~0z1Z3*8A");
|
||||
final PasswordMetrics metrics =
|
||||
PasswordMetrics.computeForPassword("6B~0z1Z3*8A".getBytes());
|
||||
assertEquals(11, metrics.length);
|
||||
assertEquals(4, metrics.letters);
|
||||
assertEquals(3, metrics.upperCase);
|
||||
@@ -93,32 +94,32 @@ public class PasswordMetricsTest {
|
||||
@Test
|
||||
public void testComputeForPassword_quality() {
|
||||
assertEquals(DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC,
|
||||
PasswordMetrics.computeForPassword("a1").quality);
|
||||
PasswordMetrics.computeForPassword("a1".getBytes()).quality);
|
||||
assertEquals(DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC,
|
||||
PasswordMetrics.computeForPassword("a").quality);
|
||||
PasswordMetrics.computeForPassword("a".getBytes()).quality);
|
||||
assertEquals(DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC,
|
||||
PasswordMetrics.computeForPassword("*~&%$").quality);
|
||||
PasswordMetrics.computeForPassword("*~&%$".getBytes()).quality);
|
||||
assertEquals(DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX,
|
||||
PasswordMetrics.computeForPassword("1").quality);
|
||||
PasswordMetrics.computeForPassword("1".getBytes()).quality);
|
||||
// contains a long sequence so isn't complex
|
||||
assertEquals(DevicePolicyManager.PASSWORD_QUALITY_NUMERIC,
|
||||
PasswordMetrics.computeForPassword("1234").quality);
|
||||
PasswordMetrics.computeForPassword("1234".getBytes()).quality);
|
||||
assertEquals(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED,
|
||||
PasswordMetrics.computeForPassword("").quality);
|
||||
PasswordMetrics.computeForPassword("".getBytes()).quality);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMaxLengthSequence() {
|
||||
assertEquals(4, PasswordMetrics.maxLengthSequence("1234"));
|
||||
assertEquals(5, PasswordMetrics.maxLengthSequence("13579"));
|
||||
assertEquals(4, PasswordMetrics.maxLengthSequence("1234abd"));
|
||||
assertEquals(3, PasswordMetrics.maxLengthSequence("aabc"));
|
||||
assertEquals(1, PasswordMetrics.maxLengthSequence("qwertyuio"));
|
||||
assertEquals(3, PasswordMetrics.maxLengthSequence("@ABC"));
|
||||
assertEquals(4, PasswordMetrics.maxLengthSequence("1234".getBytes()));
|
||||
assertEquals(5, PasswordMetrics.maxLengthSequence("13579".getBytes()));
|
||||
assertEquals(4, PasswordMetrics.maxLengthSequence("1234abd".getBytes()));
|
||||
assertEquals(3, PasswordMetrics.maxLengthSequence("aabc".getBytes()));
|
||||
assertEquals(1, PasswordMetrics.maxLengthSequence("qwertyuio".getBytes()));
|
||||
assertEquals(3, PasswordMetrics.maxLengthSequence("@ABC".getBytes()));
|
||||
// anything that repeats
|
||||
assertEquals(4, PasswordMetrics.maxLengthSequence(";;;;"));
|
||||
assertEquals(4, PasswordMetrics.maxLengthSequence(";;;;".getBytes()));
|
||||
// ordered, but not composed of alphas or digits
|
||||
assertEquals(1, PasswordMetrics.maxLengthSequence(":;<=>"));
|
||||
assertEquals(1, PasswordMetrics.maxLengthSequence(":;<=>".getBytes()));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -139,8 +140,8 @@ public class PasswordMetricsTest {
|
||||
assertNotEquals(new PasswordMetrics(DevicePolicyManager.PASSWORD_QUALITY_SOMETHING, 4),
|
||||
new PasswordMetrics(DevicePolicyManager.PASSWORD_QUALITY_COMPLEX, 4));
|
||||
|
||||
metrics0 = PasswordMetrics.computeForPassword("1234abcd,./");
|
||||
metrics1 = PasswordMetrics.computeForPassword("1234abcd,./");
|
||||
metrics0 = PasswordMetrics.computeForPassword("1234abcd,./".getBytes());
|
||||
metrics1 = PasswordMetrics.computeForPassword("1234abcd,./".getBytes());
|
||||
assertEquals(metrics0, metrics1);
|
||||
metrics1.letters++;
|
||||
assertNotEquals(metrics0, metrics1);
|
||||
@@ -161,7 +162,5 @@ public class PasswordMetricsTest {
|
||||
assertNotEquals(metrics0, metrics1);
|
||||
metrics1.nonLetter--;
|
||||
assertEquals(metrics0, metrics1);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,6 +33,8 @@ import com.android.internal.util.LatencyTracker;
|
||||
import com.android.internal.widget.LockPatternChecker;
|
||||
import com.android.internal.widget.LockPatternUtils;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* Base class for PIN and password unlock screens.
|
||||
*/
|
||||
@@ -122,18 +124,19 @@ public abstract class KeyguardAbsKeyInputView extends LinearLayout
|
||||
protected void verifyPasswordAndUnlock() {
|
||||
if (mDismissing) return; // already verified but haven't been dismissed; don't do it again.
|
||||
|
||||
final String entry = getPasswordText();
|
||||
final byte[] entry = getPasswordText();
|
||||
setPasswordEntryInputEnabled(false);
|
||||
if (mPendingLockCheck != null) {
|
||||
mPendingLockCheck.cancel(false);
|
||||
}
|
||||
|
||||
final int userId = KeyguardUpdateMonitor.getCurrentUser();
|
||||
if (entry.length() <= MINIMUM_PASSWORD_LENGTH_BEFORE_REPORT) {
|
||||
if (entry.length <= MINIMUM_PASSWORD_LENGTH_BEFORE_REPORT) {
|
||||
// to avoid accidental lockout, only count attempts that are long enough to be a
|
||||
// real password. This may require some tweaking.
|
||||
setPasswordEntryInputEnabled(true);
|
||||
onPasswordChecked(userId, false /* matched */, 0, false /* not valid - too short */);
|
||||
Arrays.fill(entry, (byte) 0);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -155,6 +158,7 @@ public abstract class KeyguardAbsKeyInputView extends LinearLayout
|
||||
}
|
||||
onPasswordChecked(userId, true /* matched */, 0 /* timeoutMs */,
|
||||
true /* isValidPassword */);
|
||||
Arrays.fill(entry, (byte) 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -169,6 +173,7 @@ public abstract class KeyguardAbsKeyInputView extends LinearLayout
|
||||
onPasswordChecked(userId, false /* matched */, timeoutMs,
|
||||
true /* isValidPassword */);
|
||||
}
|
||||
Arrays.fill(entry, (byte) 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -179,6 +184,7 @@ public abstract class KeyguardAbsKeyInputView extends LinearLayout
|
||||
LatencyTracker.getInstance(mContext).onActionEnd(
|
||||
ACTION_CHECK_CREDENTIAL_UNLOCKED);
|
||||
}
|
||||
Arrays.fill(entry, (byte) 0);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -209,7 +215,7 @@ public abstract class KeyguardAbsKeyInputView extends LinearLayout
|
||||
}
|
||||
|
||||
protected abstract void resetPasswordText(boolean animate, boolean announce);
|
||||
protected abstract String getPasswordText();
|
||||
protected abstract byte[] getPasswordText();
|
||||
protected abstract void setPasswordEntryEnabled(boolean enabled);
|
||||
protected abstract void setPasswordEntryInputEnabled(boolean enabled);
|
||||
|
||||
|
||||
@@ -231,8 +231,8 @@ public class KeyguardPasswordView extends KeyguardAbsKeyInputView
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getPasswordText() {
|
||||
return mPasswordEntry.getText().toString();
|
||||
protected byte[] getPasswordText() {
|
||||
return charSequenceToByteArray(mPasswordEntry.getText());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -366,4 +366,18 @@ public class KeyguardPasswordView extends KeyguardAbsKeyInputView
|
||||
return getContext().getString(
|
||||
com.android.internal.R.string.keyguard_accessibility_password_unlock);
|
||||
}
|
||||
|
||||
/*
|
||||
* This method avoids creating a new string when getting a byte array from EditView#getText().
|
||||
*/
|
||||
private static byte[] charSequenceToByteArray(CharSequence chars) {
|
||||
if (chars == null) {
|
||||
return null;
|
||||
}
|
||||
byte[] bytes = new byte[chars.length()];
|
||||
for (int i = 0; i < chars.length(); i++) {
|
||||
bytes[i] = (byte) chars.charAt(i);
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -161,8 +161,8 @@ public abstract class KeyguardPinBasedInputView extends KeyguardAbsKeyInputView
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getPasswordText() {
|
||||
return mPasswordEntry.getText();
|
||||
protected byte[] getPasswordText() {
|
||||
return charSequenceToByteArray(mPasswordEntry.getText());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -260,4 +260,18 @@ public abstract class KeyguardPinBasedInputView extends KeyguardAbsKeyInputView
|
||||
return getContext().getString(
|
||||
com.android.internal.R.string.keyguard_accessibility_pin_unlock);
|
||||
}
|
||||
|
||||
/*
|
||||
* This method avoids creating a new string when getting a byte array from EditView#getText().
|
||||
*/
|
||||
private static byte[] charSequenceToByteArray(CharSequence chars) {
|
||||
if (chars == null) {
|
||||
return null;
|
||||
}
|
||||
byte[] bytes = new byte[chars.length()];
|
||||
for (int i = 0; i < chars.length(); i++) {
|
||||
bytes[i] = (byte) chars.charAt(i);
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,7 +120,6 @@ import java.io.FileDescriptor;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.InvalidAlgorithmParameterException;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.KeyStoreException;
|
||||
@@ -272,7 +271,7 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
* @param managedUserPassword Managed profile original password (when it has separated lock).
|
||||
* NULL when it does not have a separated lock before.
|
||||
*/
|
||||
public void tieManagedProfileLockIfNecessary(int managedUserId, String managedUserPassword) {
|
||||
public void tieManagedProfileLockIfNecessary(int managedUserId, byte[] managedUserPassword) {
|
||||
if (DEBUG) Slog.v(TAG, "Check child profile lock for user: " + managedUserId);
|
||||
// Only for managed profile
|
||||
if (!mUserManager.getUserInfo(managedUserId).isManagedProfile()) {
|
||||
@@ -307,7 +306,12 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
byte[] randomLockSeed = new byte[] {};
|
||||
try {
|
||||
randomLockSeed = SecureRandom.getInstance("SHA1PRNG").generateSeed(40);
|
||||
String newPassword = String.valueOf(HexEncoding.encode(randomLockSeed));
|
||||
char[] newPasswordChars = HexEncoding.encode(randomLockSeed);
|
||||
byte[] newPassword = new byte[newPasswordChars.length];
|
||||
for (int i = 0; i < newPasswordChars.length; i++) {
|
||||
newPassword[i] = (byte) newPasswordChars[i];
|
||||
}
|
||||
Arrays.fill(newPasswordChars, '\u0000');
|
||||
final int quality = DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC;
|
||||
setLockCredentialInternal(newPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
|
||||
managedUserPassword, quality, managedUserId);
|
||||
@@ -316,6 +320,7 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
// password directly, so we always store a password.
|
||||
setLong(LockPatternUtils.PASSWORD_TYPE_KEY, quality, managedUserId);
|
||||
tieProfileLockToParent(managedUserId, newPassword);
|
||||
Arrays.fill(newPassword, (byte) 0);
|
||||
} catch (NoSuchAlgorithmException | RemoteException e) {
|
||||
Slog.e(TAG, "Fail to tie managed profile", e);
|
||||
// Nothing client can do to fix this issue, so we do not throw exception out
|
||||
@@ -605,7 +610,7 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
|
||||
try {
|
||||
final long handle = getSyntheticPasswordHandleLocked(userId);
|
||||
final String noCredential = null;
|
||||
final byte[] noCredential = null;
|
||||
AuthenticationResult result =
|
||||
mSpManager.unwrapPasswordBasedSyntheticPassword(
|
||||
getGateKeeperService(), handle, noCredential, userId, null);
|
||||
@@ -944,7 +949,7 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
|
||||
@Override
|
||||
public void setSeparateProfileChallengeEnabled(int userId, boolean enabled,
|
||||
String managedUserPassword) {
|
||||
byte[] managedUserPassword) {
|
||||
checkWritePermission(userId);
|
||||
synchronized (mSeparateChallengeLock) {
|
||||
setSeparateProfileChallengeEnabledLocked(userId, enabled, managedUserPassword);
|
||||
@@ -953,8 +958,8 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
}
|
||||
|
||||
@GuardedBy("mSeparateChallengeLock")
|
||||
private void setSeparateProfileChallengeEnabledLocked(@UserIdInt int userId, boolean enabled,
|
||||
String managedUserPassword) {
|
||||
private void setSeparateProfileChallengeEnabledLocked(@UserIdInt int userId,
|
||||
boolean enabled, byte[] managedUserPassword) {
|
||||
final boolean old = getBoolean(SEPARATE_PROFILE_CHALLENGE_KEY, false, userId);
|
||||
setBoolean(SEPARATE_PROFILE_CHALLENGE_KEY, enabled, userId);
|
||||
try {
|
||||
@@ -1097,24 +1102,28 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
return mStorage.hasCredential(userId);
|
||||
}
|
||||
|
||||
private void setKeystorePassword(String password, int userHandle) {
|
||||
private void setKeystorePassword(byte[] password, int userHandle) {
|
||||
final KeyStore ks = KeyStore.getInstance();
|
||||
ks.onUserPasswordChanged(userHandle, password);
|
||||
// TODO(b/120484642): Update keystore to accept byte[] passwords
|
||||
String passwordString = password == null ? null : new String(password);
|
||||
ks.onUserPasswordChanged(userHandle, passwordString);
|
||||
}
|
||||
|
||||
private void unlockKeystore(String password, int userHandle) {
|
||||
private void unlockKeystore(byte[] password, int userHandle) {
|
||||
if (DEBUG) Slog.v(TAG, "Unlock keystore for user: " + userHandle);
|
||||
// TODO(b/120484642): Update keystore to accept byte[] passwords
|
||||
String passwordString = password == null ? null : new String(password);
|
||||
final KeyStore ks = KeyStore.getInstance();
|
||||
ks.unlock(userHandle, password);
|
||||
ks.unlock(userHandle, passwordString);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
protected String getDecryptedPasswordForTiedProfile(int userId)
|
||||
protected byte[] getDecryptedPasswordForTiedProfile(int userId)
|
||||
throws KeyStoreException, UnrecoverableKeyException,
|
||||
NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException,
|
||||
InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException,
|
||||
CertificateException, IOException {
|
||||
if (DEBUG) Slog.v(TAG, "Get child profile decrytped key");
|
||||
if (DEBUG) Slog.v(TAG, "Get child profile decrypted key");
|
||||
byte[] storedData = mStorage.readChildProfileLock(userId);
|
||||
if (storedData == null) {
|
||||
throw new FileNotFoundException("Child profile lock file not found");
|
||||
@@ -1133,7 +1142,7 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
|
||||
cipher.init(Cipher.DECRYPT_MODE, decryptionKey, new GCMParameterSpec(128, iv));
|
||||
decryptionResult = cipher.doFinal(encryptedPassword);
|
||||
return new String(decryptionResult, StandardCharsets.UTF_8);
|
||||
return decryptionResult;
|
||||
}
|
||||
|
||||
private void unlockChildProfile(int profileHandle, boolean ignoreUserNotAuthenticated)
|
||||
@@ -1210,11 +1219,11 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
&& mUserManager.isUserRunning(userInfo.id);
|
||||
}
|
||||
|
||||
private Map<Integer, String> getDecryptedPasswordsForAllTiedProfiles(int userId) {
|
||||
private Map<Integer, byte[]> getDecryptedPasswordsForAllTiedProfiles(int userId) {
|
||||
if (mUserManager.getUserInfo(userId).isManagedProfile()) {
|
||||
return null;
|
||||
}
|
||||
Map<Integer, String> result = new ArrayMap<Integer, String>();
|
||||
Map<Integer, byte[]> result = new ArrayMap<Integer, byte[]>();
|
||||
final List<UserInfo> profiles = mUserManager.getProfiles(userId);
|
||||
final int size = profiles.size();
|
||||
for (int i = 0; i < size; i++) {
|
||||
@@ -1252,7 +1261,7 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
* terminates when the user is a managed profile.
|
||||
*/
|
||||
private void synchronizeUnifiedWorkChallengeForProfiles(int userId,
|
||||
Map<Integer, String> profilePasswordMap) throws RemoteException {
|
||||
Map<Integer, byte[]> profilePasswordMap) throws RemoteException {
|
||||
if (mUserManager.getUserInfo(userId).isManagedProfile()) {
|
||||
return;
|
||||
}
|
||||
@@ -1301,8 +1310,8 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
// This method should be called by LockPatternUtil only, all internal methods in this class
|
||||
// should call setLockCredentialInternal.
|
||||
@Override
|
||||
public void setLockCredential(String credential, int type, String savedCredential,
|
||||
int requestedQuality, int userId)
|
||||
public void setLockCredential(byte[] credential, int type,
|
||||
byte[] savedCredential, int requestedQuality, int userId)
|
||||
throws RemoteException {
|
||||
checkWritePermission(userId);
|
||||
synchronized (mSeparateChallengeLock) {
|
||||
@@ -1313,14 +1322,14 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
notifySeparateProfileChallengeChanged(userId);
|
||||
}
|
||||
|
||||
private void setLockCredentialInternal(String credential, int credentialType,
|
||||
String savedCredential, int requestedQuality, int userId) throws RemoteException {
|
||||
private void setLockCredentialInternal(byte[] credential, int credentialType,
|
||||
byte[] savedCredential, int requestedQuality, int userId) throws RemoteException {
|
||||
// Normalize savedCredential and credential such that empty string is always represented
|
||||
// as null.
|
||||
if (TextUtils.isEmpty(savedCredential)) {
|
||||
if (savedCredential == null || savedCredential.length == 0) {
|
||||
savedCredential = null;
|
||||
}
|
||||
if (TextUtils.isEmpty(credential)) {
|
||||
if (credential == null || credential.length == 0) {
|
||||
credential = null;
|
||||
}
|
||||
synchronized (mSpManager) {
|
||||
@@ -1389,7 +1398,7 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
mStorage.writeCredentialHash(willStore, userId);
|
||||
// push new secret and auth token to vold
|
||||
GateKeeperResponse gkResponse = getGateKeeperService()
|
||||
.verifyChallenge(userId, 0, willStore.hash, credential.getBytes());
|
||||
.verifyChallenge(userId, 0, willStore.hash, credential);
|
||||
setUserKeyProtection(userId, credential, convertResponse(gkResponse));
|
||||
fixateNewestUserKeyAuth(userId);
|
||||
// Refresh the auth token
|
||||
@@ -1409,9 +1418,8 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
protected void tieProfileLockToParent(int userId, String password) {
|
||||
protected void tieProfileLockToParent(int userId, byte[] password) {
|
||||
if (DEBUG) Slog.v(TAG, "tieProfileLockToParent for user: " + userId);
|
||||
byte[] randomLockSeed = password.getBytes(StandardCharsets.UTF_8);
|
||||
byte[] encryptionResult;
|
||||
byte[] iv;
|
||||
try {
|
||||
@@ -1445,7 +1453,7 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
KeyProperties.KEY_ALGORITHM_AES + "/" + KeyProperties.BLOCK_MODE_GCM + "/"
|
||||
+ KeyProperties.ENCRYPTION_PADDING_NONE);
|
||||
cipher.init(Cipher.ENCRYPT_MODE, keyStoreEncryptionKey);
|
||||
encryptionResult = cipher.doFinal(randomLockSeed);
|
||||
encryptionResult = cipher.doFinal(password);
|
||||
iv = cipher.getIV();
|
||||
} finally {
|
||||
// The original key can now be discarded.
|
||||
@@ -1470,17 +1478,11 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
}
|
||||
|
||||
private byte[] enrollCredential(byte[] enrolledHandle,
|
||||
String enrolledCredential, String toEnroll, int userId)
|
||||
byte[] enrolledCredential, byte[] toEnroll, int userId)
|
||||
throws RemoteException {
|
||||
checkWritePermission(userId);
|
||||
byte[] enrolledCredentialBytes = enrolledCredential == null
|
||||
? null
|
||||
: enrolledCredential.getBytes();
|
||||
byte[] toEnrollBytes = toEnroll == null
|
||||
? null
|
||||
: toEnroll.getBytes();
|
||||
GateKeeperResponse response = getGateKeeperService().enroll(userId, enrolledHandle,
|
||||
enrolledCredentialBytes, toEnrollBytes);
|
||||
enrolledCredential, toEnroll);
|
||||
|
||||
if (response == null) {
|
||||
return null;
|
||||
@@ -1501,7 +1503,7 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
addUserKeyAuth(userId, null, key);
|
||||
}
|
||||
|
||||
private void setUserKeyProtection(int userId, String credential, VerifyCredentialResponse vcr)
|
||||
private void setUserKeyProtection(int userId, byte[] credential, VerifyCredentialResponse vcr)
|
||||
throws RemoteException {
|
||||
if (DEBUG) Slog.d(TAG, "setUserKeyProtection: user=" + userId);
|
||||
if (vcr == null) {
|
||||
@@ -1523,16 +1525,15 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
addUserKeyAuth(userId, null, null);
|
||||
}
|
||||
|
||||
private static byte[] secretFromCredential(String credential) throws RemoteException {
|
||||
private static byte[] secretFromCredential(byte[] credential) throws RemoteException {
|
||||
try {
|
||||
MessageDigest digest = MessageDigest.getInstance("SHA-512");
|
||||
// Personalize the hash
|
||||
byte[] personalization = "Android FBE credential hash"
|
||||
.getBytes(StandardCharsets.UTF_8);
|
||||
byte[] personalization = "Android FBE credential hash".getBytes();
|
||||
// Pad it to the block size of the hash function
|
||||
personalization = Arrays.copyOf(personalization, 128);
|
||||
digest.update(personalization);
|
||||
digest.update(credential.getBytes(StandardCharsets.UTF_8));
|
||||
digest.update(credential);
|
||||
return digest.digest();
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new RuntimeException("NoSuchAlgorithmException for SHA-512");
|
||||
@@ -1568,7 +1569,7 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
checkWritePermission(userId);
|
||||
if (DEBUG) Slog.v(TAG, "Reset keystore for user: " + userId);
|
||||
int managedUserId = -1;
|
||||
String managedUserDecryptedPassword = null;
|
||||
byte[] managedUserDecryptedPassword = null;
|
||||
final List<UserInfo> profiles = mUserManager.getProfiles(userId);
|
||||
for (UserInfo pi : profiles) {
|
||||
// Unlock managed profile with unified lock
|
||||
@@ -1605,17 +1606,20 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
tieProfileLockToParent(managedUserId, managedUserDecryptedPassword);
|
||||
}
|
||||
}
|
||||
if (managedUserDecryptedPassword != null && managedUserDecryptedPassword.length > 0) {
|
||||
Arrays.fill(managedUserDecryptedPassword, (byte) 0);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public VerifyCredentialResponse checkCredential(String credential, int type, int userId,
|
||||
public VerifyCredentialResponse checkCredential(byte[] credential, int type, int userId,
|
||||
ICheckCredentialProgressCallback progressCallback) throws RemoteException {
|
||||
checkPasswordReadPermission(userId);
|
||||
return doVerifyCredential(credential, type, false, 0, userId, progressCallback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public VerifyCredentialResponse verifyCredential(String credential, int type, long challenge,
|
||||
public VerifyCredentialResponse verifyCredential(byte[] credential, int type, long challenge,
|
||||
int userId) throws RemoteException {
|
||||
checkPasswordReadPermission(userId);
|
||||
return doVerifyCredential(credential, type, true, challenge, userId,
|
||||
@@ -1626,10 +1630,10 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
* Verify user credential and unlock the user. Fix pattern bug by deprecating the old base zero
|
||||
* format.
|
||||
*/
|
||||
private VerifyCredentialResponse doVerifyCredential(String credential, int credentialType,
|
||||
private VerifyCredentialResponse doVerifyCredential(byte[] credential, int credentialType,
|
||||
boolean hasChallenge, long challenge, int userId,
|
||||
ICheckCredentialProgressCallback progressCallback) throws RemoteException {
|
||||
if (TextUtils.isEmpty(credential)) {
|
||||
if (credential == null || credential.length == 0) {
|
||||
throw new IllegalArgumentException("Credential can't be null or empty");
|
||||
}
|
||||
if (userId == USER_FRP && Settings.Global.getInt(mContext.getContentResolver(),
|
||||
@@ -1664,9 +1668,9 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
boolean shouldReEnrollBaseZero = storedHash.type == LockPatternUtils.CREDENTIAL_TYPE_PATTERN
|
||||
&& storedHash.isBaseZeroPattern;
|
||||
|
||||
String credentialToVerify;
|
||||
byte[] credentialToVerify;
|
||||
if (shouldReEnrollBaseZero) {
|
||||
credentialToVerify = LockPatternUtils.patternStringToBaseZero(credential);
|
||||
credentialToVerify = LockPatternUtils.patternByteArrayToBaseZero(credential);
|
||||
} else {
|
||||
credentialToVerify = credential;
|
||||
}
|
||||
@@ -1686,7 +1690,7 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
}
|
||||
|
||||
@Override
|
||||
public VerifyCredentialResponse verifyTiedProfileChallenge(String credential, int type,
|
||||
public VerifyCredentialResponse verifyTiedProfileChallenge(byte[] credential, int type,
|
||||
long challenge, int userId) throws RemoteException {
|
||||
checkPasswordReadPermission(userId);
|
||||
if (!isManagedProfileWithUnifiedLock(userId)) {
|
||||
@@ -1728,14 +1732,15 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
* hash to GK.
|
||||
*/
|
||||
private VerifyCredentialResponse verifyCredential(int userId, CredentialHash storedHash,
|
||||
String credential, boolean hasChallenge, long challenge,
|
||||
byte[] credential, boolean hasChallenge, long challenge,
|
||||
ICheckCredentialProgressCallback progressCallback) throws RemoteException {
|
||||
if ((storedHash == null || storedHash.hash.length == 0) && TextUtils.isEmpty(credential)) {
|
||||
if ((storedHash == null || storedHash.hash.length == 0)
|
||||
&& (credential == null || credential.length == 0)) {
|
||||
// don't need to pass empty credentials to GateKeeper
|
||||
return VerifyCredentialResponse.OK;
|
||||
}
|
||||
|
||||
if (storedHash == null || TextUtils.isEmpty(credential)) {
|
||||
if (storedHash == null || credential == null || credential.length == 0) {
|
||||
return VerifyCredentialResponse.ERROR;
|
||||
}
|
||||
|
||||
@@ -1746,14 +1751,14 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
if (storedHash.version == CredentialHash.VERSION_LEGACY) {
|
||||
final byte[] hash;
|
||||
if (storedHash.type == LockPatternUtils.CREDENTIAL_TYPE_PATTERN) {
|
||||
hash = LockPatternUtils.patternToHash(LockPatternUtils.stringToPattern(credential));
|
||||
hash = LockPatternUtils.patternToHash(
|
||||
LockPatternUtils.byteArrayToPattern(credential));
|
||||
} else {
|
||||
hash = mLockPatternUtils.legacyPasswordToHash(credential, userId)
|
||||
.getBytes(StandardCharsets.UTF_8);
|
||||
hash = mLockPatternUtils.legacyPasswordToHash(credential, userId).getBytes();
|
||||
}
|
||||
if (Arrays.equals(hash, storedHash.hash)) {
|
||||
if (storedHash.type == LockPatternUtils.CREDENTIAL_TYPE_PATTERN) {
|
||||
unlockKeystore(LockPatternUtils.patternStringToBaseZero(credential), userId);
|
||||
unlockKeystore(LockPatternUtils.patternByteArrayToBaseZero(credential), userId);
|
||||
} else {
|
||||
unlockKeystore(credential, userId);
|
||||
}
|
||||
@@ -1784,7 +1789,7 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
}
|
||||
}
|
||||
GateKeeperResponse gateKeeperResponse = getGateKeeperService()
|
||||
.verifyChallenge(userId, challenge, storedHash.hash, credential.getBytes());
|
||||
.verifyChallenge(userId, challenge, storedHash.hash, credential);
|
||||
VerifyCredentialResponse response = convertResponse(gateKeeperResponse);
|
||||
boolean shouldReEnroll = gateKeeperResponse.getShouldReEnroll();
|
||||
|
||||
@@ -1843,7 +1848,7 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
* Call this method to notify DPMS regarding the latest password metric. This should be called
|
||||
* when the user is authenticating or when a new password is being set.
|
||||
*/
|
||||
private void notifyActivePasswordMetricsAvailable(String password, @UserIdInt int userId) {
|
||||
private void notifyActivePasswordMetricsAvailable(byte[] password, @UserIdInt int userId) {
|
||||
final PasswordMetrics metrics;
|
||||
if (password == null) {
|
||||
metrics = new PasswordMetrics();
|
||||
@@ -1891,6 +1896,7 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
// service can't connect to vold, it restarts, and then the new instance
|
||||
// does successfully connect.
|
||||
final IStorageManager service = mInjector.getStorageManager();
|
||||
// TODO(b/120484642): Update vold to return a password as a byte array
|
||||
String password;
|
||||
long identity = Binder.clearCallingIdentity();
|
||||
try {
|
||||
@@ -1905,8 +1911,8 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
|
||||
try {
|
||||
if (mLockPatternUtils.isLockPatternEnabled(userId)) {
|
||||
if (checkCredential(password, LockPatternUtils.CREDENTIAL_TYPE_PATTERN, userId,
|
||||
null /* progressCallback */)
|
||||
if (checkCredential(password.getBytes(), LockPatternUtils.CREDENTIAL_TYPE_PATTERN,
|
||||
userId, null /* progressCallback */)
|
||||
.getResponseCode() == GateKeeperResponse.RESPONSE_OK) {
|
||||
return true;
|
||||
}
|
||||
@@ -1916,8 +1922,8 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
|
||||
try {
|
||||
if (mLockPatternUtils.isLockPasswordEnabled(userId)) {
|
||||
if (checkCredential(password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, userId,
|
||||
null /* progressCallback */)
|
||||
if (checkCredential(password.getBytes(), LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
|
||||
userId, null /* progressCallback */)
|
||||
.getResponseCode() == GateKeeperResponse.RESPONSE_OK) {
|
||||
return true;
|
||||
}
|
||||
@@ -2283,7 +2289,7 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
@GuardedBy("mSpManager")
|
||||
@VisibleForTesting
|
||||
protected AuthenticationToken initializeSyntheticPasswordLocked(byte[] credentialHash,
|
||||
String credential, int credentialType, int requestedQuality,
|
||||
byte[] credential, int credentialType, int requestedQuality,
|
||||
int userId) throws RemoteException {
|
||||
Slog.i(TAG, "Initialize SyntheticPassword for user: " + userId);
|
||||
final AuthenticationToken auth = mSpManager.newSyntheticPasswordAndSid(
|
||||
@@ -2344,7 +2350,7 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
setLong(SYNTHETIC_PASSWORD_ENABLED_KEY, 1, UserHandle.USER_SYSTEM);
|
||||
}
|
||||
|
||||
private VerifyCredentialResponse spBasedDoVerifyCredential(String userCredential, int
|
||||
private VerifyCredentialResponse spBasedDoVerifyCredential(byte[] userCredential, int
|
||||
credentialType, boolean hasChallenge, long challenge, int userId,
|
||||
ICheckCredentialProgressCallback progressCallback) throws RemoteException {
|
||||
if (DEBUG) Slog.d(TAG, "spBasedDoVerifyCredential: user=" + userId);
|
||||
@@ -2424,12 +2430,12 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
* added back when new password is set in future.
|
||||
*/
|
||||
@GuardedBy("mSpManager")
|
||||
private long setLockCredentialWithAuthTokenLocked(String credential, int credentialType,
|
||||
private long setLockCredentialWithAuthTokenLocked(byte[] credential, int credentialType,
|
||||
AuthenticationToken auth, int requestedQuality, int userId) throws RemoteException {
|
||||
if (DEBUG) Slog.d(TAG, "setLockCredentialWithAuthTokenLocked: user=" + userId);
|
||||
long newHandle = mSpManager.createPasswordBasedSyntheticPassword(getGateKeeperService(),
|
||||
credential, credentialType, auth, requestedQuality, userId);
|
||||
final Map<Integer, String> profilePasswords;
|
||||
final Map<Integer, byte[]> profilePasswords;
|
||||
if (credential != null) {
|
||||
// // not needed by synchronizeUnifiedWorkChallengeForProfiles()
|
||||
profilePasswords = null;
|
||||
@@ -2468,12 +2474,19 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
synchronizeUnifiedWorkChallengeForProfiles(userId, profilePasswords);
|
||||
|
||||
notifyActivePasswordMetricsAvailable(credential, userId);
|
||||
|
||||
if (profilePasswords != null) {
|
||||
for (Map.Entry<Integer, byte[]> entry : profilePasswords.entrySet()) {
|
||||
Arrays.fill(entry.getValue(), (byte) 0);
|
||||
}
|
||||
}
|
||||
|
||||
return newHandle;
|
||||
}
|
||||
|
||||
@GuardedBy("mSpManager")
|
||||
private void spBasedSetLockCredentialInternalLocked(String credential, int credentialType,
|
||||
String savedCredential, int requestedQuality, int userId) throws RemoteException {
|
||||
private void spBasedSetLockCredentialInternalLocked(byte[] credential, int credentialType,
|
||||
byte[] savedCredential, int requestedQuality, int userId) throws RemoteException {
|
||||
if (DEBUG) Slog.d(TAG, "spBasedSetLockCredentialInternalLocked: user=" + userId);
|
||||
if (isManagedProfileWithUnifiedLock(userId)) {
|
||||
// get credential from keystore when managed profile has unified lock
|
||||
@@ -2546,9 +2559,9 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
* If user is a managed profile with unified challenge, currentCredential is ignored.
|
||||
*/
|
||||
@Override
|
||||
public byte[] getHashFactor(String currentCredential, int userId) throws RemoteException {
|
||||
public byte[] getHashFactor(byte[] currentCredential, int userId) throws RemoteException {
|
||||
checkPasswordReadPermission(userId);
|
||||
if (TextUtils.isEmpty(currentCredential)) {
|
||||
if (currentCredential == null || currentCredential.length == 0) {
|
||||
currentCredential = null;
|
||||
}
|
||||
if (isManagedProfileWithUnifiedLock(userId)) {
|
||||
@@ -2642,7 +2655,7 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean setLockCredentialWithToken(String credential, int type, long tokenHandle,
|
||||
private boolean setLockCredentialWithToken(byte[] credential, int type, long tokenHandle,
|
||||
byte[] token, int requestedQuality, int userId) throws RemoteException {
|
||||
boolean result;
|
||||
synchronized (mSpManager) {
|
||||
@@ -2662,7 +2675,7 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
return result;
|
||||
}
|
||||
|
||||
private boolean setLockCredentialWithTokenInternal(String credential, int type,
|
||||
private boolean setLockCredentialWithTokenInternal(byte[] credential, int type,
|
||||
long tokenHandle, byte[] token, int requestedQuality, int userId) throws RemoteException {
|
||||
final AuthenticationResult result;
|
||||
synchronized (mSpManager) {
|
||||
@@ -2889,8 +2902,8 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setLockCredentialWithToken(String credential, int type, long tokenHandle,
|
||||
byte[] token, int requestedQuality, int userId) {
|
||||
public boolean setLockCredentialWithToken(byte[] credential, int type,
|
||||
long tokenHandle, byte[] token, int requestedQuality, int userId) {
|
||||
try {
|
||||
return LockSettingsService.this.setLockCredentialWithToken(credential, type,
|
||||
tokenHandle, token, requestedQuality, userId);
|
||||
|
||||
@@ -134,23 +134,31 @@ class LockSettingsShellCommand extends ShellCommand {
|
||||
mLockPatternUtils.isSyntheticPasswordEnabled()));
|
||||
}
|
||||
|
||||
private void runSetPattern() throws RemoteException {
|
||||
mLockPatternUtils.saveLockPattern(stringToPattern(mNew), mOld, mCurrentUserId);
|
||||
private void runSetPattern() {
|
||||
byte[] oldBytes = mOld != null ? mOld.getBytes() : null;
|
||||
mLockPatternUtils.saveLockPattern(stringToPattern(mNew), oldBytes, mCurrentUserId);
|
||||
getOutPrintWriter().println("Pattern set to '" + mNew + "'");
|
||||
}
|
||||
|
||||
private void runSetPassword() throws RemoteException {
|
||||
mLockPatternUtils.saveLockPassword(mNew, mOld, PASSWORD_QUALITY_ALPHABETIC, mCurrentUserId);
|
||||
private void runSetPassword() {
|
||||
byte[] newBytes = mNew != null ? mNew.getBytes() : null;
|
||||
byte[] oldBytes = mOld != null ? mOld.getBytes() : null;
|
||||
mLockPatternUtils.saveLockPassword(newBytes, oldBytes, PASSWORD_QUALITY_ALPHABETIC,
|
||||
mCurrentUserId);
|
||||
getOutPrintWriter().println("Password set to '" + mNew + "'");
|
||||
}
|
||||
|
||||
private void runSetPin() throws RemoteException {
|
||||
mLockPatternUtils.saveLockPassword(mNew, mOld, PASSWORD_QUALITY_NUMERIC, mCurrentUserId);
|
||||
private void runSetPin() {
|
||||
byte[] newBytes = mNew != null ? mNew.getBytes() : null;
|
||||
byte[] oldBytes = mOld != null ? mOld.getBytes() : null;
|
||||
mLockPatternUtils.saveLockPassword(newBytes, oldBytes, PASSWORD_QUALITY_NUMERIC,
|
||||
mCurrentUserId);
|
||||
getOutPrintWriter().println("Pin set to '" + mNew + "'");
|
||||
}
|
||||
|
||||
private void runClear() throws RemoteException {
|
||||
mLockPatternUtils.clearLock(mOld, mCurrentUserId);
|
||||
private void runClear() {
|
||||
byte[] oldBytes = mOld != null ? mOld.getBytes() : null;
|
||||
mLockPatternUtils.clearLock(oldBytes, mCurrentUserId);
|
||||
getOutPrintWriter().println("Lock credential cleared");
|
||||
}
|
||||
|
||||
@@ -177,7 +185,8 @@ class LockSettingsShellCommand extends ShellCommand {
|
||||
try {
|
||||
final boolean result;
|
||||
if (havePassword) {
|
||||
result = mLockPatternUtils.checkPassword(mOld, mCurrentUserId);
|
||||
byte[] passwordBytes = mOld != null ? mOld.getBytes() : null;
|
||||
result = mLockPatternUtils.checkPassword(passwordBytes, mCurrentUserId);
|
||||
} else {
|
||||
result = mLockPatternUtils.checkPattern(stringToPattern(mOld), mCurrentUserId);
|
||||
}
|
||||
|
||||
@@ -96,7 +96,7 @@ public class SyntheticPasswordManager {
|
||||
private static final String WEAVER_SLOT_NAME = "weaver";
|
||||
|
||||
public static final long DEFAULT_HANDLE = 0L;
|
||||
private static final String DEFAULT_PASSWORD = "default-password";
|
||||
private static final byte[] DEFAULT_PASSWORD = "default-password".getBytes();
|
||||
|
||||
private static final byte WEAVER_VERSION = 1;
|
||||
private static final int INVALID_WEAVER_SLOT = -1;
|
||||
@@ -164,7 +164,7 @@ public class SyntheticPasswordManager {
|
||||
}
|
||||
}
|
||||
|
||||
public String deriveKeyStorePassword() {
|
||||
public byte[] deriveKeyStorePassword() {
|
||||
return bytesToHex(derivePassword(PERSONALIZATION_KEY_STORE_PASSWORD));
|
||||
}
|
||||
|
||||
@@ -453,11 +453,11 @@ public class SyntheticPasswordManager {
|
||||
*
|
||||
*/
|
||||
public AuthenticationToken newSyntheticPasswordAndSid(IGateKeeperService gatekeeper,
|
||||
byte[] hash, String credential, int userId) throws RemoteException {
|
||||
byte[] hash, byte[] credential, int userId) throws RemoteException {
|
||||
AuthenticationToken result = AuthenticationToken.create();
|
||||
GateKeeperResponse response;
|
||||
if (hash != null) {
|
||||
response = gatekeeper.enroll(userId, hash, credential.getBytes(),
|
||||
response = gatekeeper.enroll(userId, hash, credential,
|
||||
result.deriveGkPassword());
|
||||
if (response.getResponseCode() != GateKeeperResponse.RESPONSE_OK) {
|
||||
Log.w(TAG, "Fail to migrate SID, assuming no SID, user " + userId);
|
||||
@@ -615,7 +615,7 @@ public class SyntheticPasswordManager {
|
||||
* @see #clearSidForUser
|
||||
*/
|
||||
public long createPasswordBasedSyntheticPassword(IGateKeeperService gatekeeper,
|
||||
String credential, int credentialType, AuthenticationToken authToken,
|
||||
byte[] credential, int credentialType, AuthenticationToken authToken,
|
||||
int requestedQuality, int userId)
|
||||
throws RemoteException {
|
||||
if (credential == null || credentialType == LockPatternUtils.CREDENTIAL_TYPE_NONE) {
|
||||
@@ -669,7 +669,7 @@ public class SyntheticPasswordManager {
|
||||
}
|
||||
|
||||
public VerifyCredentialResponse verifyFrpCredential(IGateKeeperService gatekeeper,
|
||||
String userCredential, int credentialType,
|
||||
byte[] userCredential, int credentialType,
|
||||
ICheckCredentialProgressCallback progressCallback) throws RemoteException {
|
||||
PersistentData persistentData = mStorage.readPersistentDataBlock();
|
||||
if (persistentData.type == PersistentData.TYPE_SP) {
|
||||
@@ -838,7 +838,7 @@ public class SyntheticPasswordManager {
|
||||
* unknown. Caller might choose to validate it by examining AuthenticationResult.credentialType
|
||||
*/
|
||||
public AuthenticationResult unwrapPasswordBasedSyntheticPassword(IGateKeeperService gatekeeper,
|
||||
long handle, String credential, int userId,
|
||||
long handle, byte[] credential, int userId,
|
||||
ICheckCredentialProgressCallback progressCallback) throws RemoteException {
|
||||
if (credential == null) {
|
||||
credential = DEFAULT_PASSWORD;
|
||||
@@ -1151,7 +1151,7 @@ public class SyntheticPasswordManager {
|
||||
return String.format("%s%x", LockPatternUtils.SYNTHETIC_PASSWORD_KEY_PREFIX, handle);
|
||||
}
|
||||
|
||||
private byte[] computePasswordToken(String password, PasswordData data) {
|
||||
private byte[] computePasswordToken(byte[] password, PasswordData data) {
|
||||
return scrypt(password, data.salt, 1 << data.scryptN, 1 << data.scryptR, 1 << data.scryptP,
|
||||
PASSWORD_TOKEN_LENGTH);
|
||||
}
|
||||
@@ -1172,8 +1172,8 @@ public class SyntheticPasswordManager {
|
||||
return nativeSidFromPasswordHandle(handle);
|
||||
}
|
||||
|
||||
protected byte[] scrypt(String password, byte[] salt, int N, int r, int p, int outLen) {
|
||||
return nativeScrypt(password.getBytes(), salt, N, r, p, outLen);
|
||||
protected byte[] scrypt(byte[] password, byte[] salt, int N, int r, int p, int outLen) {
|
||||
return nativeScrypt(password, salt, N, r, p, outLen);
|
||||
}
|
||||
|
||||
native long nativeSidFromPasswordHandle(byte[] handle);
|
||||
@@ -1195,17 +1195,17 @@ public class SyntheticPasswordManager {
|
||||
return result;
|
||||
}
|
||||
|
||||
final protected static char[] hexArray = "0123456789ABCDEF".toCharArray();
|
||||
public static String bytesToHex(byte[] bytes) {
|
||||
protected static final byte[] HEX_ARRAY = "0123456789ABCDEF".getBytes();
|
||||
private static byte[] bytesToHex(byte[] bytes) {
|
||||
if (bytes == null) {
|
||||
return "null";
|
||||
return "null".getBytes();
|
||||
}
|
||||
char[] hexChars = new char[bytes.length * 2];
|
||||
byte[] hexBytes = new byte[bytes.length * 2];
|
||||
for ( int j = 0; j < bytes.length; j++ ) {
|
||||
int v = bytes[j] & 0xFF;
|
||||
hexChars[j * 2] = hexArray[v >>> 4];
|
||||
hexChars[j * 2 + 1] = hexArray[v & 0x0F];
|
||||
hexBytes[j * 2] = HEX_ARRAY[v >>> 4];
|
||||
hexBytes[j * 2 + 1] = HEX_ARRAY[v & 0x0F];
|
||||
}
|
||||
return new String(hexChars);
|
||||
return hexBytes;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,7 +36,6 @@ import com.android.server.locksettings.recoverablekeystore.storage.RecoverySnaps
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.security.InvalidAlgorithmParameterException;
|
||||
import java.security.InvalidKeyException;
|
||||
@@ -49,6 +48,7 @@ import java.security.UnrecoverableKeyException;
|
||||
import java.security.cert.CertPath;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -83,7 +83,7 @@ public class KeySyncTask implements Runnable {
|
||||
private final RecoverableKeyStoreDb mRecoverableKeyStoreDb;
|
||||
private final int mUserId;
|
||||
private final int mCredentialType;
|
||||
private final String mCredential;
|
||||
private final byte[] mCredential;
|
||||
private final boolean mCredentialUpdated;
|
||||
private final PlatformKeyManager mPlatformKeyManager;
|
||||
private final RecoverySnapshotStorage mRecoverySnapshotStorage;
|
||||
@@ -98,7 +98,7 @@ public class KeySyncTask implements Runnable {
|
||||
RecoverySnapshotListenersStorage recoverySnapshotListenersStorage,
|
||||
int userId,
|
||||
int credentialType,
|
||||
String credential,
|
||||
byte[] credential,
|
||||
boolean credentialUpdated
|
||||
) throws NoSuchAlgorithmException, KeyStoreException, InsecureUserException {
|
||||
return new KeySyncTask(
|
||||
@@ -132,7 +132,7 @@ public class KeySyncTask implements Runnable {
|
||||
RecoverySnapshotListenersStorage recoverySnapshotListenersStorage,
|
||||
int userId,
|
||||
int credentialType,
|
||||
String credential,
|
||||
byte[] credential,
|
||||
boolean credentialUpdated,
|
||||
PlatformKeyManager platformKeyManager,
|
||||
TestOnlyInsecureCertificateHelper testOnlyInsecureCertificateHelper,
|
||||
@@ -445,7 +445,7 @@ public class KeySyncTask implements Runnable {
|
||||
*/
|
||||
@VisibleForTesting
|
||||
@KeyChainProtectionParams.LockScreenUiFormat static int getUiFormat(
|
||||
int credentialType, String credential) {
|
||||
int credentialType, byte[] credential) {
|
||||
if (credentialType == LockPatternUtils.CREDENTIAL_TYPE_PATTERN) {
|
||||
return KeyChainProtectionParams.UI_FORMAT_PATTERN;
|
||||
} else if (isPin(credential)) {
|
||||
@@ -470,13 +470,13 @@ public class KeySyncTask implements Runnable {
|
||||
* Returns {@code true} if {@code credential} looks like a pin.
|
||||
*/
|
||||
@VisibleForTesting
|
||||
static boolean isPin(@Nullable String credential) {
|
||||
static boolean isPin(@Nullable byte[] credential) {
|
||||
if (credential == null) {
|
||||
return false;
|
||||
}
|
||||
int length = credential.length();
|
||||
int length = credential.length;
|
||||
for (int i = 0; i < length; i++) {
|
||||
if (!Character.isDigit(credential.charAt(i))) {
|
||||
if (!Character.isDigit((char) credential[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -489,8 +489,7 @@ public class KeySyncTask implements Runnable {
|
||||
* @return The SHA-256 hash.
|
||||
*/
|
||||
@VisibleForTesting
|
||||
static byte[] hashCredentialsBySaltedSha256(byte[] salt, String credentials) {
|
||||
byte[] credentialsBytes = credentials.getBytes(StandardCharsets.UTF_8);
|
||||
static byte[] hashCredentialsBySaltedSha256(byte[] salt, byte[] credentialsBytes) {
|
||||
ByteBuffer byteBuffer = ByteBuffer.allocate(
|
||||
salt.length + credentialsBytes.length + LENGTH_PREFIX_BYTES * 2);
|
||||
byteBuffer.order(ByteOrder.LITTLE_ENDIAN);
|
||||
@@ -501,17 +500,19 @@ public class KeySyncTask implements Runnable {
|
||||
byte[] bytes = byteBuffer.array();
|
||||
|
||||
try {
|
||||
return MessageDigest.getInstance(LOCK_SCREEN_HASH_ALGORITHM).digest(bytes);
|
||||
byte[] hash = MessageDigest.getInstance(LOCK_SCREEN_HASH_ALGORITHM).digest(bytes);
|
||||
Arrays.fill(bytes, (byte) 0);
|
||||
return hash;
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
// Impossible, SHA-256 must be supported on Android.
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] hashCredentialsByScrypt(byte[] salt, String credentials) {
|
||||
private byte[] hashCredentialsByScrypt(byte[] salt, byte[] credentials) {
|
||||
return mScrypt.scrypt(
|
||||
credentials.getBytes(StandardCharsets.UTF_8), salt,
|
||||
SCRYPT_PARAM_N, SCRYPT_PARAM_R, SCRYPT_PARAM_P, SCRYPT_PARAM_OUTLEN_BYTES);
|
||||
credentials, salt, SCRYPT_PARAM_N, SCRYPT_PARAM_R, SCRYPT_PARAM_P,
|
||||
SCRYPT_PARAM_OUTLEN_BYTES);
|
||||
}
|
||||
|
||||
private static SecretKey generateRecoveryKey() throws NoSuchAlgorithmException {
|
||||
|
||||
@@ -851,13 +851,13 @@ public class RecoverableKeyStoreManager {
|
||||
* This function can only be used inside LockSettingsService.
|
||||
*
|
||||
* @param storedHashType from {@code CredentialHash}
|
||||
* @param credential - unencrypted String. Password length should be at most 16 symbols {@code
|
||||
* mPasswordMaxLength}
|
||||
* @param credential - unencrypted byte array. Password length should be at most 16 symbols
|
||||
* {@code mPasswordMaxLength}
|
||||
* @param userId for user who just unlocked the device.
|
||||
* @hide
|
||||
*/
|
||||
public void lockScreenSecretAvailable(
|
||||
int storedHashType, @NonNull String credential, int userId) {
|
||||
int storedHashType, @NonNull byte[] credential, int userId) {
|
||||
// So as not to block the critical path unlocking the phone, defer to another thread.
|
||||
try {
|
||||
mExecutorService.execute(KeySyncTask.newInstance(
|
||||
@@ -882,13 +882,13 @@ public class RecoverableKeyStoreManager {
|
||||
* This function can only be used inside LockSettingsService.
|
||||
*
|
||||
* @param storedHashType from {@code CredentialHash}
|
||||
* @param credential - unencrypted String
|
||||
* @param credential - unencrypted byte array
|
||||
* @param userId for the user whose lock screen credentials were changed.
|
||||
* @hide
|
||||
*/
|
||||
public void lockScreenSecretChanged(
|
||||
int storedHashType,
|
||||
@Nullable String credential,
|
||||
@Nullable byte[] credential,
|
||||
int userId) {
|
||||
// So as not to block the critical path unlocking the phone, defer to another thread.
|
||||
try {
|
||||
|
||||
@@ -84,10 +84,30 @@ public class TestOnlyInsecureCertificateHelper {
|
||||
|| isTestOnlyCertificateAlias(rootCertificateAlias);
|
||||
}
|
||||
|
||||
public boolean doesCredentialSupportInsecureMode(int credentialType, String credential) {
|
||||
return (credentialType == LockPatternUtils.CREDENTIAL_TYPE_PASSWORD)
|
||||
&& (credential != null)
|
||||
&& credential.startsWith(TrustedRootCertificates.INSECURE_PASSWORD_PREFIX);
|
||||
/**
|
||||
* Checks whether a password is in "Insecure mode"
|
||||
* @param credentialType the type of credential, e.g. pattern and password
|
||||
* @param credential the pattern or password
|
||||
* @return true, if the credential is in "Insecure mode"
|
||||
*/
|
||||
public boolean doesCredentialSupportInsecureMode(int credentialType, byte[] credential) {
|
||||
if (credential == null) {
|
||||
return false;
|
||||
}
|
||||
if (credentialType != LockPatternUtils.CREDENTIAL_TYPE_PASSWORD) {
|
||||
return false;
|
||||
}
|
||||
byte[] insecurePasswordPrefixBytes =
|
||||
TrustedRootCertificates.INSECURE_PASSWORD_PREFIX.getBytes();
|
||||
if (credential.length < insecurePasswordPrefixBytes.length) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < insecurePasswordPrefixBytes.length; i++) {
|
||||
if (credential[i] != insecurePasswordPrefixBytes[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public Map<String, SecretKey> keepOnlyWhitelistedInsecureKeys(Map<String, SecretKey> rawKeys) {
|
||||
|
||||
@@ -4794,7 +4794,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
|
||||
if (quality == DevicePolicyManager.PASSWORD_QUALITY_MANAGED) {
|
||||
quality = PASSWORD_QUALITY_UNSPECIFIED;
|
||||
}
|
||||
final PasswordMetrics metrics = PasswordMetrics.computeForPassword(password);
|
||||
// TODO(b/120484642): remove getBytes() below
|
||||
final PasswordMetrics metrics = PasswordMetrics.computeForPassword(password.getBytes());
|
||||
final int realQuality = metrics.quality;
|
||||
if (realQuality < quality
|
||||
&& quality != DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
|
||||
@@ -4881,16 +4882,22 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
|
||||
try {
|
||||
if (token == null) {
|
||||
if (!TextUtils.isEmpty(password)) {
|
||||
mLockPatternUtils.saveLockPassword(password, null, quality, userHandle);
|
||||
mLockPatternUtils.saveLockPassword(password.getBytes(), null, quality,
|
||||
userHandle);
|
||||
} else {
|
||||
mLockPatternUtils.clearLock(null, userHandle);
|
||||
}
|
||||
result = true;
|
||||
} else {
|
||||
result = mLockPatternUtils.setLockCredentialWithToken(password,
|
||||
TextUtils.isEmpty(password) ? LockPatternUtils.CREDENTIAL_TYPE_NONE
|
||||
: LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
|
||||
quality, tokenHandle, token, userHandle);
|
||||
if (!TextUtils.isEmpty(password)) {
|
||||
result = mLockPatternUtils.setLockCredentialWithToken(password.getBytes(),
|
||||
LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
|
||||
quality, tokenHandle, token, userHandle);
|
||||
} else {
|
||||
result = mLockPatternUtils.setLockCredentialWithToken(null,
|
||||
LockPatternUtils.CREDENTIAL_TYPE_NONE,
|
||||
quality, tokenHandle, token, userHandle);
|
||||
}
|
||||
}
|
||||
boolean requireEntry = (flags & DevicePolicyManager.RESET_PASSWORD_REQUIRE_ENTRY) != 0;
|
||||
if (requireEntry) {
|
||||
|
||||
@@ -4179,7 +4179,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
|
||||
assertTrue(dpm.isResetPasswordTokenActive(admin1));
|
||||
|
||||
// test reset password with token
|
||||
when(getServices().lockPatternUtils.setLockCredentialWithToken(eq(password),
|
||||
when(getServices().lockPatternUtils.setLockCredentialWithToken(eq(password.getBytes()),
|
||||
eq(LockPatternUtils.CREDENTIAL_TYPE_PASSWORD),
|
||||
eq(DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC), eq(handle), eq(token),
|
||||
eq(UserHandle.USER_SYSTEM)))
|
||||
|
||||
@@ -18,24 +18,22 @@ package com.android.server.locksettings;
|
||||
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC;
|
||||
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
|
||||
|
||||
import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PASSWORD;
|
||||
import static com.android.server.testutils.TestUtils.assertExpectException;
|
||||
|
||||
import static org.mockito.Mockito.anyInt;
|
||||
import static org.mockito.Mockito.atLeastOnce;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.os.RemoteException;
|
||||
|
||||
import com.android.internal.widget.LockPatternUtils;
|
||||
import com.android.internal.widget.VerifyCredentialResponse;
|
||||
import com.android.server.locksettings.SyntheticPasswordManager.AuthenticationResult;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import org.mockito.ArgumentCaptor;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* Run the synthetic password tests with caching enabled.
|
||||
*
|
||||
@@ -56,10 +54,10 @@ public class CachedSyntheticPasswordTests extends SyntheticPasswordTests {
|
||||
}
|
||||
|
||||
public void testSyntheticPasswordClearCredentialUntrusted() throws RemoteException {
|
||||
final String PASSWORD = "testSyntheticPasswordClearCredential-password";
|
||||
final String NEWPASSWORD = "testSyntheticPasswordClearCredential-newpassword";
|
||||
final byte[] password = "testSyntheticPasswordClearCredential-password".getBytes();
|
||||
final byte[] newPassword = "testSyntheticPasswordClearCredential-newpassword".getBytes();
|
||||
|
||||
initializeCredentialUnderSP(PASSWORD, PRIMARY_USER_ID);
|
||||
initializeCredentialUnderSP(password, PRIMARY_USER_ID);
|
||||
long sid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID);
|
||||
// clear password
|
||||
mService.setLockCredential(null, LockPatternUtils.CREDENTIAL_TYPE_NONE, null,
|
||||
@@ -67,45 +65,46 @@ public class CachedSyntheticPasswordTests extends SyntheticPasswordTests {
|
||||
assertEquals(0, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
|
||||
|
||||
// set a new password
|
||||
mService.setLockCredential(NEWPASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
|
||||
mService.setLockCredential(newPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
|
||||
PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
|
||||
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
|
||||
NEWPASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
|
||||
.getResponseCode());
|
||||
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(newPassword,
|
||||
LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
|
||||
.getResponseCode());
|
||||
assertNotEquals(sid, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
|
||||
}
|
||||
|
||||
public void testSyntheticPasswordChangeCredentialUntrusted() throws RemoteException {
|
||||
final String PASSWORD = "testSyntheticPasswordClearCredential-password";
|
||||
final String NEWPASSWORD = "testSyntheticPasswordClearCredential-newpassword";
|
||||
final byte[] password = "testSyntheticPasswordClearCredential-password".getBytes();
|
||||
final byte[] newPassword = "testSyntheticPasswordClearCredential-newpassword".getBytes();
|
||||
|
||||
initializeCredentialUnderSP(PASSWORD, PRIMARY_USER_ID);
|
||||
initializeCredentialUnderSP(password, PRIMARY_USER_ID);
|
||||
long sid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID);
|
||||
// Untrusted change password
|
||||
mService.setLockCredential(NEWPASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
|
||||
mService.setLockCredential(newPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
|
||||
PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
|
||||
assertNotEquals(0, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
|
||||
assertNotEquals(sid, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
|
||||
|
||||
// Verify the password
|
||||
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
|
||||
NEWPASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
|
||||
.getResponseCode());
|
||||
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(newPassword,
|
||||
LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID).getResponseCode());
|
||||
}
|
||||
|
||||
public void testUntrustedCredentialChangeMaintainsAuthSecret() throws RemoteException {
|
||||
final String PASSWORD = "testUntrustedCredentialChangeMaintainsAuthSecret-password";
|
||||
final String NEWPASSWORD = "testUntrustedCredentialChangeMaintainsAuthSecret-newpassword";
|
||||
final byte[] password =
|
||||
"testUntrustedCredentialChangeMaintainsAuthSecret-password".getBytes();
|
||||
final byte[] newPassword =
|
||||
"testUntrustedCredentialChangeMaintainsAuthSecret-newpassword".getBytes();
|
||||
|
||||
initializeCredentialUnderSP(PASSWORD, PRIMARY_USER_ID);
|
||||
initializeCredentialUnderSP(password, PRIMARY_USER_ID);
|
||||
// Untrusted change password
|
||||
mService.setLockCredential(NEWPASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
|
||||
mService.setLockCredential(newPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
|
||||
PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
|
||||
|
||||
// Verify the password
|
||||
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
|
||||
NEWPASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
|
||||
.getResponseCode());
|
||||
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(newPassword,
|
||||
LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
|
||||
.getResponseCode());
|
||||
|
||||
// Ensure the same secret was passed each time
|
||||
ArgumentCaptor<ArrayList<Byte>> secret = ArgumentCaptor.forClass(ArrayList.class);
|
||||
@@ -114,27 +113,29 @@ public class CachedSyntheticPasswordTests extends SyntheticPasswordTests {
|
||||
}
|
||||
|
||||
public void testUntrustedCredentialChangeBlockedIfSpNotCached() throws RemoteException {
|
||||
final String PASSWORD = "testUntrustedCredentialChangeBlockedIfSpNotCached-password";
|
||||
final String NEWPASSWORD = "testUntrustedCredentialChangeBlockedIfSpNotCached-newpassword";
|
||||
final byte[] password =
|
||||
"testUntrustedCredentialChangeBlockedIfSpNotCached-password".getBytes();
|
||||
final byte[] newPassword =
|
||||
"testUntrustedCredentialChangeBlockedIfSpNotCached-newpassword".getBytes();
|
||||
|
||||
// Disable caching for this test
|
||||
enableSpCaching(false);
|
||||
|
||||
initializeCredentialUnderSP(PASSWORD, PRIMARY_USER_ID);
|
||||
initializeCredentialUnderSP(password, PRIMARY_USER_ID);
|
||||
long sid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID);
|
||||
// Untrusted change password
|
||||
assertExpectException(IllegalStateException.class, /* messageRegex= */ null,
|
||||
() -> mService.setLockCredential(
|
||||
NEWPASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
|
||||
null, PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID));
|
||||
() -> mService.setLockCredential(newPassword,
|
||||
LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
|
||||
PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID));
|
||||
assertEquals(sid, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
|
||||
|
||||
// Verify the new password doesn't work but the old one still does
|
||||
assertEquals(VerifyCredentialResponse.RESPONSE_ERROR, mService.verifyCredential(
|
||||
NEWPASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
|
||||
assertEquals(VerifyCredentialResponse.RESPONSE_ERROR, mService.verifyCredential(newPassword,
|
||||
LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
|
||||
.getResponseCode());
|
||||
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
|
||||
PASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
|
||||
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(password,
|
||||
LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
|
||||
.getResponseCode());
|
||||
}
|
||||
|
||||
|
||||
@@ -120,12 +120,12 @@ public class LockSettingsServiceTestable extends LockSettingsService {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void tieProfileLockToParent(int userId, String password) {
|
||||
mStorage.writeChildProfileLock(userId, password.getBytes());
|
||||
protected void tieProfileLockToParent(int userId, byte[] password) {
|
||||
mStorage.writeChildProfileLock(userId, password);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getDecryptedPasswordForTiedProfile(int userId) throws FileNotFoundException,
|
||||
protected byte[] getDecryptedPasswordForTiedProfile(int userId) throws FileNotFoundException,
|
||||
KeyPermanentlyInvalidatedException {
|
||||
byte[] storedData = mStorage.readChildProfileLock(userId);
|
||||
if (storedData == null) {
|
||||
@@ -138,7 +138,7 @@ public class LockSettingsServiceTestable extends LockSettingsService {
|
||||
} catch (RemoteException e) {
|
||||
// shouldn't happen.
|
||||
}
|
||||
return new String(storedData);
|
||||
return storedData;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -75,8 +75,8 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests {
|
||||
initializeStorageWithCredential(PRIMARY_USER_ID, "password", CREDENTIAL_TYPE_PASSWORD, sid);
|
||||
|
||||
try {
|
||||
mService.setLockCredential("newpwd", CREDENTIAL_TYPE_PASSWORD, "badpwd",
|
||||
PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
|
||||
mService.setLockCredential("newpwd".getBytes(), CREDENTIAL_TYPE_PASSWORD,
|
||||
"badpwd".getBytes(), PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
|
||||
fail("Did not fail when enrolling using incorrect credential");
|
||||
} catch (RemoteException expected) {
|
||||
assertTrue(expected.getMessage().equals(FAILED_MESSAGE));
|
||||
@@ -87,7 +87,7 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests {
|
||||
public void testClearPasswordPrimaryUser() throws RemoteException {
|
||||
final String PASSWORD = "password";
|
||||
initializeStorageWithCredential(PRIMARY_USER_ID, PASSWORD, CREDENTIAL_TYPE_PASSWORD, 1234);
|
||||
mService.setLockCredential(null, CREDENTIAL_TYPE_NONE, PASSWORD,
|
||||
mService.setLockCredential(null, CREDENTIAL_TYPE_NONE, PASSWORD.getBytes(),
|
||||
PASSWORD_QUALITY_UNSPECIFIED, PRIMARY_USER_ID);
|
||||
assertFalse(mService.havePassword(PRIMARY_USER_ID));
|
||||
assertFalse(mService.havePattern(PRIMARY_USER_ID));
|
||||
@@ -97,7 +97,8 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests {
|
||||
public void testManagedProfileUnifiedChallenge() throws RemoteException {
|
||||
final String firstUnifiedPassword = "testManagedProfileUnifiedChallenge-pwd-1";
|
||||
final String secondUnifiedPassword = "testManagedProfileUnifiedChallenge-pwd-2";
|
||||
mService.setLockCredential(firstUnifiedPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
|
||||
mService.setLockCredential(firstUnifiedPassword.getBytes(),
|
||||
LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
|
||||
null, PASSWORD_QUALITY_COMPLEX, PRIMARY_USER_ID);
|
||||
mService.setSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID, false, null);
|
||||
final long primarySid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID);
|
||||
@@ -116,8 +117,8 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests {
|
||||
mGateKeeperService.clearAuthToken(TURNED_OFF_PROFILE_USER_ID);
|
||||
// verify credential
|
||||
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
|
||||
firstUnifiedPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
|
||||
.getResponseCode());
|
||||
firstUnifiedPassword.getBytes(), LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0,
|
||||
PRIMARY_USER_ID).getResponseCode());
|
||||
|
||||
// Verify that we have a new auth token for the profile
|
||||
assertNotNull(mGateKeeperService.getAuthToken(MANAGED_PROFILE_USER_ID));
|
||||
@@ -132,15 +133,16 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests {
|
||||
*/
|
||||
mStorageManager.setIgnoreBadUnlock(true);
|
||||
// Change primary password and verify that profile SID remains
|
||||
mService.setLockCredential(secondUnifiedPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
|
||||
firstUnifiedPassword, PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
|
||||
mService.setLockCredential(secondUnifiedPassword.getBytes(),
|
||||
LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
|
||||
firstUnifiedPassword.getBytes(), PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
|
||||
mStorageManager.setIgnoreBadUnlock(false);
|
||||
assertEquals(profileSid, mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID));
|
||||
assertNull(mGateKeeperService.getAuthToken(TURNED_OFF_PROFILE_USER_ID));
|
||||
|
||||
// Clear unified challenge
|
||||
mService.setLockCredential(null, LockPatternUtils.CREDENTIAL_TYPE_NONE,
|
||||
secondUnifiedPassword, PASSWORD_QUALITY_UNSPECIFIED, PRIMARY_USER_ID);
|
||||
secondUnifiedPassword.getBytes(), PASSWORD_QUALITY_UNSPECIFIED, PRIMARY_USER_ID);
|
||||
assertEquals(0, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
|
||||
assertEquals(0, mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID));
|
||||
assertEquals(0, mGateKeeperService.getSecureUserId(TURNED_OFF_PROFILE_USER_ID));
|
||||
@@ -149,14 +151,16 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests {
|
||||
public void testManagedProfileSeparateChallenge() throws RemoteException {
|
||||
final String primaryPassword = "testManagedProfileSeparateChallenge-primary";
|
||||
final String profilePassword = "testManagedProfileSeparateChallenge-profile";
|
||||
mService.setLockCredential(primaryPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
|
||||
mService.setLockCredential(primaryPassword.getBytes(),
|
||||
LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
|
||||
PASSWORD_QUALITY_COMPLEX, PRIMARY_USER_ID);
|
||||
/* Currently in LockSettingsService.setLockCredential, unlockUser() is called with the new
|
||||
* credential as part of verifyCredential() before the new credential is committed in
|
||||
* StorageManager. So we relax the check in our mock StorageManager to allow that.
|
||||
*/
|
||||
mStorageManager.setIgnoreBadUnlock(true);
|
||||
mService.setLockCredential(profilePassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
|
||||
mService.setLockCredential(profilePassword.getBytes(),
|
||||
LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
|
||||
PASSWORD_QUALITY_COMPLEX, MANAGED_PROFILE_USER_ID);
|
||||
mStorageManager.setIgnoreBadUnlock(false);
|
||||
|
||||
@@ -170,31 +174,32 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests {
|
||||
mGateKeeperService.clearAuthToken(MANAGED_PROFILE_USER_ID);
|
||||
// verify primary credential
|
||||
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
|
||||
primaryPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
|
||||
.getResponseCode());
|
||||
primaryPassword.getBytes(), LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0,
|
||||
PRIMARY_USER_ID).getResponseCode());
|
||||
assertNull(mGateKeeperService.getAuthToken(MANAGED_PROFILE_USER_ID));
|
||||
|
||||
// verify profile credential
|
||||
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
|
||||
profilePassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0,
|
||||
profilePassword.getBytes(), LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0,
|
||||
MANAGED_PROFILE_USER_ID).getResponseCode());
|
||||
assertNotNull(mGateKeeperService.getAuthToken(MANAGED_PROFILE_USER_ID));
|
||||
assertEquals(profileSid, mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID));
|
||||
|
||||
// Change primary credential and make sure we don't affect profile
|
||||
mStorageManager.setIgnoreBadUnlock(true);
|
||||
mService.setLockCredential("pwd", LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
|
||||
primaryPassword, PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
|
||||
mService.setLockCredential("pwd".getBytes(), LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
|
||||
primaryPassword.getBytes(), PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
|
||||
mStorageManager.setIgnoreBadUnlock(false);
|
||||
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
|
||||
profilePassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0,
|
||||
profilePassword.getBytes(), LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0,
|
||||
MANAGED_PROFILE_USER_ID).getResponseCode());
|
||||
assertEquals(profileSid, mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID));
|
||||
}
|
||||
|
||||
private void testCreateCredential(int userId, String credential, int type, int quality)
|
||||
throws RemoteException {
|
||||
mService.setLockCredential(credential, type, null, quality, userId);
|
||||
mService.setLockCredential(credential.getBytes(), type, null, quality,
|
||||
userId);
|
||||
assertVerifyCredentials(userId, credential, type, -1);
|
||||
}
|
||||
|
||||
@@ -202,15 +207,16 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests {
|
||||
String oldCredential, int oldType, int quality) throws RemoteException {
|
||||
final long sid = 1234;
|
||||
initializeStorageWithCredential(userId, oldCredential, oldType, sid);
|
||||
mService.setLockCredential(newCredential, newType, oldCredential, quality, userId);
|
||||
mService.setLockCredential(newCredential.getBytes(), newType, oldCredential.getBytes(),
|
||||
quality, userId);
|
||||
assertVerifyCredentials(userId, newCredential, newType, sid);
|
||||
}
|
||||
|
||||
private void assertVerifyCredentials(int userId, String credential, int type, long sid)
|
||||
throws RemoteException{
|
||||
final long challenge = 54321;
|
||||
VerifyCredentialResponse response = mService.verifyCredential(credential, type, challenge,
|
||||
userId);
|
||||
VerifyCredentialResponse response = mService.verifyCredential(credential.getBytes(),
|
||||
type, challenge, userId);
|
||||
|
||||
assertEquals(GateKeeperResponse.RESPONSE_OK, response.getResponseCode());
|
||||
if (sid != -1) assertEquals(sid, mGateKeeperService.getSecureUserId(userId));
|
||||
@@ -229,18 +235,19 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests {
|
||||
incorrectType = LockPatternUtils.CREDENTIAL_TYPE_PASSWORD;
|
||||
}
|
||||
// check for bad type
|
||||
assertEquals(GateKeeperResponse.RESPONSE_ERROR, mService.verifyCredential(credential,
|
||||
incorrectType, challenge, userId).getResponseCode());
|
||||
assertEquals(GateKeeperResponse.RESPONSE_ERROR, mService.verifyCredential(
|
||||
credential.getBytes(), incorrectType, challenge, userId).getResponseCode());
|
||||
// check for bad credential
|
||||
assertEquals(GateKeeperResponse.RESPONSE_ERROR, mService.verifyCredential("0" + credential,
|
||||
type, challenge, userId).getResponseCode());
|
||||
assertEquals(GateKeeperResponse.RESPONSE_ERROR, mService.verifyCredential(
|
||||
("0" + credential).getBytes(), type, challenge, userId).getResponseCode());
|
||||
}
|
||||
|
||||
private void initializeStorageWithCredential(int userId, String credential, int type, long sid)
|
||||
throws RemoteException {
|
||||
byte[] credentialBytes = credential == null ? null : credential.getBytes();
|
||||
byte[] oldHash = new VerifyHandle(credential.getBytes(), sid).toBytes();
|
||||
if (mService.shouldMigrateToSyntheticPasswordLocked(userId)) {
|
||||
mService.initializeSyntheticPasswordLocked(oldHash, credential, type,
|
||||
mService.initializeSyntheticPasswordLocked(oldHash, credentialBytes, type,
|
||||
type == LockPatternUtils.CREDENTIAL_TYPE_PASSWORD ? PASSWORD_QUALITY_ALPHABETIC
|
||||
: PASSWORD_QUALITY_SOMETHING, userId);
|
||||
} else {
|
||||
|
||||
@@ -87,35 +87,36 @@ public class LockSettingsShellCommandTest {
|
||||
public void testWrongPassword() throws Exception {
|
||||
when(mLockPatternUtils.isLockPatternEnabled(mUserId)).thenReturn(false);
|
||||
when(mLockPatternUtils.isLockPasswordEnabled(mUserId)).thenReturn(true);
|
||||
when(mLockPatternUtils.checkPassword("1234", mUserId)).thenReturn(false);
|
||||
when(mLockPatternUtils.checkPassword("1234".getBytes(), mUserId)).thenReturn(false);
|
||||
assertEquals(-1, mCommand.exec(mBinder, in, out, err,
|
||||
new String[] { "set-pin", "--old", "1234" },
|
||||
mShellCallback, mResultReceiver));
|
||||
verify(mLockPatternUtils, never()).saveLockPassword(any(), any(), anyInt(), anyInt());
|
||||
verify(mLockPatternUtils, never()).saveLockPassword(any(byte[].class), any(byte[].class),
|
||||
anyInt(), anyInt());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testChangePin() throws Exception {
|
||||
when(mLockPatternUtils.isLockPatternEnabled(mUserId)).thenReturn(false);
|
||||
when(mLockPatternUtils.isLockPasswordEnabled(mUserId)).thenReturn(true);
|
||||
when(mLockPatternUtils.checkPassword("1234", mUserId)).thenReturn(true);
|
||||
when(mLockPatternUtils.checkPassword("1234".getBytes(), mUserId)).thenReturn(true);
|
||||
assertEquals(0, mCommand.exec(new Binder(), in, out, err,
|
||||
new String[] { "set-pin", "--old", "1234", "4321" },
|
||||
mShellCallback, mResultReceiver));
|
||||
verify(mLockPatternUtils).saveLockPassword("4321", "1234", PASSWORD_QUALITY_NUMERIC,
|
||||
mUserId);
|
||||
verify(mLockPatternUtils).saveLockPassword("4321".getBytes(), "1234".getBytes(),
|
||||
PASSWORD_QUALITY_NUMERIC, mUserId);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testChangePassword() throws Exception {
|
||||
when(mLockPatternUtils.isLockPatternEnabled(mUserId)).thenReturn(false);
|
||||
when(mLockPatternUtils.isLockPasswordEnabled(mUserId)).thenReturn(true);
|
||||
when(mLockPatternUtils.checkPassword("1234", mUserId)).thenReturn(true);
|
||||
when(mLockPatternUtils.checkPassword("1234".getBytes(), mUserId)).thenReturn(true);
|
||||
assertEquals(0, mCommand.exec(new Binder(), in, out, err,
|
||||
new String[] { "set-password", "--old", "1234", "4321" },
|
||||
mShellCallback, mResultReceiver));
|
||||
verify(mLockPatternUtils).saveLockPassword("4321", "1234", PASSWORD_QUALITY_ALPHABETIC,
|
||||
mUserId);
|
||||
verify(mLockPatternUtils).saveLockPassword("4321".getBytes(), "1234".getBytes(),
|
||||
PASSWORD_QUALITY_ALPHABETIC, mUserId);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -126,7 +127,8 @@ public class LockSettingsShellCommandTest {
|
||||
assertEquals(0, mCommand.exec(new Binder(), in, out, err,
|
||||
new String[] { "set-pattern", "--old", "1234", "4321" },
|
||||
mShellCallback, mResultReceiver));
|
||||
verify(mLockPatternUtils).saveLockPattern(stringToPattern("4321"), "1234", mUserId);
|
||||
verify(mLockPatternUtils).saveLockPattern(stringToPattern("4321"), "1234".getBytes(),
|
||||
mUserId);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -137,6 +139,6 @@ public class LockSettingsShellCommandTest {
|
||||
assertEquals(0, mCommand.exec(new Binder(), in, out, err,
|
||||
new String[] { "clear", "--old", "1234" },
|
||||
mShellCallback, mResultReceiver));
|
||||
verify(mLockPatternUtils).clearLock("1234", mUserId);
|
||||
verify(mLockPatternUtils).clearLock("1234".getBytes(), mUserId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,9 +93,13 @@ public class MockSyntheticPasswordManager extends SyntheticPasswordManager {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected byte[] scrypt(String password, byte[] salt, int N, int r, int p, int outLen) {
|
||||
protected byte[] scrypt(byte[] password, byte[] salt, int n, int r, int p, int outLen) {
|
||||
try {
|
||||
PBEKeySpec spec = new PBEKeySpec(password.toCharArray(), salt, 10, outLen * 8);
|
||||
char[] passwordChars = new char[password.length];
|
||||
for (int i = 0; i < password.length; i++) {
|
||||
passwordChars[i] = (char) password[i];
|
||||
}
|
||||
PBEKeySpec spec = new PBEKeySpec(passwordChars, salt, 10, outLen * 8);
|
||||
SecretKeyFactory f = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
|
||||
return f.generateSecret(spec).getEncoded();
|
||||
} catch (InvalidKeySpecException | NoSuchAlgorithmException e) {
|
||||
|
||||
@@ -65,22 +65,23 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests {
|
||||
|
||||
public void testPasswordBasedSyntheticPassword() throws RemoteException {
|
||||
final int USER_ID = 10;
|
||||
final String PASSWORD = "user-password";
|
||||
final String BADPASSWORD = "bad-password";
|
||||
final byte[] password = "user-password".getBytes();
|
||||
final byte[] badPassword = "bad-password".getBytes();
|
||||
MockSyntheticPasswordManager manager = new MockSyntheticPasswordManager(mContext, mStorage,
|
||||
mGateKeeperService, mUserManager);
|
||||
AuthenticationToken authToken = manager.newSyntheticPasswordAndSid(mGateKeeperService, null,
|
||||
null, USER_ID);
|
||||
long handle = manager.createPasswordBasedSyntheticPassword(mGateKeeperService, PASSWORD,
|
||||
LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, authToken, PASSWORD_QUALITY_ALPHABETIC,
|
||||
USER_ID);
|
||||
long handle = manager.createPasswordBasedSyntheticPassword(mGateKeeperService,
|
||||
password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, authToken,
|
||||
PASSWORD_QUALITY_ALPHABETIC, USER_ID);
|
||||
|
||||
AuthenticationResult result = manager.unwrapPasswordBasedSyntheticPassword(
|
||||
mGateKeeperService, handle, PASSWORD, USER_ID, null);
|
||||
assertEquals(result.authToken.deriveKeyStorePassword(), authToken.deriveKeyStorePassword());
|
||||
mGateKeeperService, handle, password, USER_ID, null);
|
||||
assertArrayEquals(result.authToken.deriveKeyStorePassword(),
|
||||
authToken.deriveKeyStorePassword());
|
||||
|
||||
result = manager.unwrapPasswordBasedSyntheticPassword(mGateKeeperService, handle,
|
||||
BADPASSWORD, USER_ID, null);
|
||||
badPassword, USER_ID, null);
|
||||
assertNull(result.authToken);
|
||||
}
|
||||
|
||||
@@ -97,30 +98,30 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests {
|
||||
}
|
||||
|
||||
public void testPasswordMigration() throws RemoteException {
|
||||
final String PASSWORD = "testPasswordMigration-password";
|
||||
final byte[] password = "testPasswordMigration-password".getBytes();
|
||||
|
||||
disableSyntheticPassword();
|
||||
mService.setLockCredential(PASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
|
||||
mService.setLockCredential(password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
|
||||
PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
|
||||
long sid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID);
|
||||
final byte[] primaryStorageKey = mStorageManager.getUserUnlockToken(PRIMARY_USER_ID);
|
||||
enableSyntheticPassword();
|
||||
// Performs migration
|
||||
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
|
||||
PASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
|
||||
password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
|
||||
.getResponseCode());
|
||||
assertEquals(sid, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
|
||||
assertTrue(hasSyntheticPassword(PRIMARY_USER_ID));
|
||||
|
||||
// SP-based verification
|
||||
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
|
||||
PASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
|
||||
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(password,
|
||||
LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
|
||||
.getResponseCode());
|
||||
assertArrayNotEquals(primaryStorageKey,
|
||||
mStorageManager.getUserUnlockToken(PRIMARY_USER_ID));
|
||||
}
|
||||
|
||||
protected void initializeCredentialUnderSP(String password, int userId) throws RemoteException {
|
||||
protected void initializeCredentialUnderSP(byte[] password, int userId) throws RemoteException {
|
||||
enableSyntheticPassword();
|
||||
int quality = password != null ? PASSWORD_QUALITY_ALPHABETIC
|
||||
: PASSWORD_QUALITY_UNSPECIFIED;
|
||||
@@ -130,62 +131,64 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests {
|
||||
}
|
||||
|
||||
public void testSyntheticPasswordChangeCredential() throws RemoteException {
|
||||
final String PASSWORD = "testSyntheticPasswordChangeCredential-password";
|
||||
final String NEWPASSWORD = "testSyntheticPasswordChangeCredential-newpassword";
|
||||
final byte[] password = "testSyntheticPasswordChangeCredential-password".getBytes();
|
||||
final byte[] newPassword = "testSyntheticPasswordChangeCredential-newpassword".getBytes();
|
||||
|
||||
initializeCredentialUnderSP(PASSWORD, PRIMARY_USER_ID);
|
||||
initializeCredentialUnderSP(password, PRIMARY_USER_ID);
|
||||
long sid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID);
|
||||
mService.setLockCredential(NEWPASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, PASSWORD,
|
||||
mService.setLockCredential(newPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, password,
|
||||
PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
|
||||
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
|
||||
NEWPASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
|
||||
newPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
|
||||
.getResponseCode());
|
||||
assertEquals(sid, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
|
||||
}
|
||||
|
||||
public void testSyntheticPasswordVerifyCredential() throws RemoteException {
|
||||
final String PASSWORD = "testSyntheticPasswordVerifyCredential-password";
|
||||
final String BADPASSWORD = "testSyntheticPasswordVerifyCredential-badpassword";
|
||||
final byte[] password = "testSyntheticPasswordVerifyCredential-password".getBytes();
|
||||
final byte[] badPassword = "testSyntheticPasswordVerifyCredential-badpassword".getBytes();
|
||||
|
||||
initializeCredentialUnderSP(PASSWORD, PRIMARY_USER_ID);
|
||||
initializeCredentialUnderSP(password, PRIMARY_USER_ID);
|
||||
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
|
||||
PASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
|
||||
password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
|
||||
.getResponseCode());
|
||||
|
||||
assertEquals(VerifyCredentialResponse.RESPONSE_ERROR, mService.verifyCredential(
|
||||
BADPASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
|
||||
.getResponseCode());
|
||||
badPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
|
||||
.getResponseCode());
|
||||
}
|
||||
|
||||
public void testSyntheticPasswordClearCredential() throws RemoteException {
|
||||
final String PASSWORD = "testSyntheticPasswordClearCredential-password";
|
||||
final String NEWPASSWORD = "testSyntheticPasswordClearCredential-newpassword";
|
||||
final byte[] password = "testSyntheticPasswordClearCredential-password".getBytes();
|
||||
final byte[] badPassword = "testSyntheticPasswordClearCredential-newpassword".getBytes();
|
||||
|
||||
initializeCredentialUnderSP(PASSWORD, PRIMARY_USER_ID);
|
||||
initializeCredentialUnderSP(password, PRIMARY_USER_ID);
|
||||
long sid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID);
|
||||
// clear password
|
||||
mService.setLockCredential(null, LockPatternUtils.CREDENTIAL_TYPE_NONE, PASSWORD,
|
||||
mService.setLockCredential(null, LockPatternUtils.CREDENTIAL_TYPE_NONE, password,
|
||||
PASSWORD_QUALITY_UNSPECIFIED, PRIMARY_USER_ID);
|
||||
assertEquals(0 ,mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
|
||||
|
||||
// set a new password
|
||||
mService.setLockCredential(NEWPASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
|
||||
mService.setLockCredential(badPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
|
||||
PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
|
||||
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
|
||||
NEWPASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
|
||||
.getResponseCode());
|
||||
badPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
|
||||
.getResponseCode());
|
||||
assertNotEquals(sid, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
|
||||
}
|
||||
|
||||
public void testSyntheticPasswordChangeCredentialKeepsAuthSecret() throws RemoteException {
|
||||
final String PASSWORD = "testSyntheticPasswordChangeCredentialKeepsAuthSecret-password";
|
||||
final String NEWPASSWORD = "testSyntheticPasswordChangeCredentialKeepsAuthSecret-new";
|
||||
final byte[] password =
|
||||
"testSyntheticPasswordChangeCredentialKeepsAuthSecret-password".getBytes();
|
||||
final byte[] badPassword =
|
||||
"testSyntheticPasswordChangeCredentialKeepsAuthSecret-new".getBytes();
|
||||
|
||||
initializeCredentialUnderSP(PASSWORD, PRIMARY_USER_ID);
|
||||
mService.setLockCredential(NEWPASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, PASSWORD,
|
||||
initializeCredentialUnderSP(password, PRIMARY_USER_ID);
|
||||
mService.setLockCredential(badPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, password,
|
||||
PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
|
||||
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
|
||||
NEWPASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
|
||||
badPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
|
||||
.getResponseCode());
|
||||
|
||||
// Check the same secret was passed each time
|
||||
@@ -195,24 +198,25 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests {
|
||||
}
|
||||
|
||||
public void testSyntheticPasswordVerifyPassesPrimaryUserAuthSecret() throws RemoteException {
|
||||
final String PASSWORD = "testSyntheticPasswordVerifyPassesPrimaryUserAuthSecret-password";
|
||||
final String NEWPASSWORD = "testSyntheticPasswordVerifyPassesPrimaryUserAuthSecret-new";
|
||||
final byte[] password =
|
||||
"testSyntheticPasswordVerifyPassesPrimaryUserAuthSecret-password".getBytes();
|
||||
final byte[] newPassword =
|
||||
"testSyntheticPasswordVerifyPassesPrimaryUserAuthSecret-new".getBytes();
|
||||
|
||||
initializeCredentialUnderSP(PASSWORD, PRIMARY_USER_ID);
|
||||
initializeCredentialUnderSP(password, PRIMARY_USER_ID);
|
||||
reset(mAuthSecretService);
|
||||
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
|
||||
PASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
|
||||
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(password,
|
||||
LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
|
||||
.getResponseCode());
|
||||
verify(mAuthSecretService).primaryUserCredential(any(ArrayList.class));
|
||||
}
|
||||
|
||||
public void testSecondaryUserDoesNotPassAuthSecret() throws RemoteException {
|
||||
final String PASSWORD = "testSecondaryUserDoesNotPassAuthSecret-password";
|
||||
final String NEWPASSWORD = "testSecondaryUserDoesNotPassAuthSecret-new";
|
||||
final byte[] password = "testSecondaryUserDoesNotPassAuthSecret-password".getBytes();
|
||||
|
||||
initializeCredentialUnderSP(PASSWORD, SECONDARY_USER_ID);
|
||||
initializeCredentialUnderSP(password, SECONDARY_USER_ID);
|
||||
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
|
||||
PASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, SECONDARY_USER_ID)
|
||||
password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, SECONDARY_USER_ID)
|
||||
.getResponseCode());
|
||||
verify(mAuthSecretService, never()).primaryUserCredential(any(ArrayList.class));
|
||||
}
|
||||
@@ -228,8 +232,8 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests {
|
||||
}
|
||||
|
||||
public void testSyntheticPasswordAndCredentialDoesNotPassAuthSecret() throws RemoteException {
|
||||
final String PASSWORD = "passwordForASyntheticPassword";
|
||||
initializeCredentialUnderSP(PASSWORD, PRIMARY_USER_ID);
|
||||
final byte[] password = "passwordForASyntheticPassword".getBytes();
|
||||
initializeCredentialUnderSP(password, PRIMARY_USER_ID);
|
||||
|
||||
reset(mAuthSecretService);
|
||||
mService.onUnlockUser(PRIMARY_USER_ID);
|
||||
@@ -238,9 +242,9 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests {
|
||||
}
|
||||
|
||||
public void testSyntheticPasswordButNoCredentialPassesAuthSecret() throws RemoteException {
|
||||
final String PASSWORD = "getASyntheticPassword";
|
||||
initializeCredentialUnderSP(PASSWORD, PRIMARY_USER_ID);
|
||||
mService.setLockCredential(null, LockPatternUtils.CREDENTIAL_TYPE_NONE, PASSWORD,
|
||||
final byte[] password = "getASyntheticPassword".getBytes();
|
||||
initializeCredentialUnderSP(password, PRIMARY_USER_ID);
|
||||
mService.setLockCredential(null, LockPatternUtils.CREDENTIAL_TYPE_NONE, password,
|
||||
PASSWORD_QUALITY_UNSPECIFIED, PRIMARY_USER_ID);
|
||||
|
||||
reset(mAuthSecretService);
|
||||
@@ -250,7 +254,7 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests {
|
||||
}
|
||||
|
||||
public void testManagedProfileUnifiedChallengeMigration() throws RemoteException {
|
||||
final String UnifiedPassword = "testManagedProfileUnifiedChallengeMigration-pwd";
|
||||
final byte[] UnifiedPassword = "testManagedProfileUnifiedChallengeMigration-pwd".getBytes();
|
||||
disableSyntheticPassword();
|
||||
mService.setLockCredential(UnifiedPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
|
||||
PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
|
||||
@@ -284,8 +288,10 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests {
|
||||
}
|
||||
|
||||
public void testManagedProfileSeparateChallengeMigration() throws RemoteException {
|
||||
final String primaryPassword = "testManagedProfileSeparateChallengeMigration-primary";
|
||||
final String profilePassword = "testManagedProfileSeparateChallengeMigration-profile";
|
||||
final byte[] primaryPassword =
|
||||
"testManagedProfileSeparateChallengeMigration-primary".getBytes();
|
||||
final byte[] profilePassword =
|
||||
"testManagedProfileSeparateChallengeMigration-profile".getBytes();
|
||||
disableSyntheticPassword();
|
||||
mService.setLockCredential(primaryPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
|
||||
PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
|
||||
@@ -326,92 +332,92 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests {
|
||||
}
|
||||
|
||||
public void testTokenBasedResetPassword() throws RemoteException {
|
||||
final String PASSWORD = "password";
|
||||
final String PATTERN = "123654";
|
||||
final String TOKEN = "some-high-entropy-secure-token";
|
||||
initializeCredentialUnderSP(PASSWORD, PRIMARY_USER_ID);
|
||||
final byte[] password = "password".getBytes();
|
||||
final byte[] pattern = "123654".getBytes();
|
||||
final byte[] token = "some-high-entropy-secure-token".getBytes();
|
||||
initializeCredentialUnderSP(password, PRIMARY_USER_ID);
|
||||
final byte[] storageKey = mStorageManager.getUserUnlockToken(PRIMARY_USER_ID);
|
||||
|
||||
long handle = mLocalService.addEscrowToken(TOKEN.getBytes(), PRIMARY_USER_ID);
|
||||
long handle = mLocalService.addEscrowToken(token, PRIMARY_USER_ID);
|
||||
assertFalse(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
|
||||
|
||||
mService.verifyCredential(PASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0,
|
||||
mService.verifyCredential(password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0,
|
||||
PRIMARY_USER_ID).getResponseCode();
|
||||
assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
|
||||
|
||||
mLocalService.setLockCredentialWithToken(PATTERN, LockPatternUtils.CREDENTIAL_TYPE_PATTERN,
|
||||
handle, TOKEN.getBytes(), PASSWORD_QUALITY_SOMETHING, PRIMARY_USER_ID);
|
||||
mLocalService.setLockCredentialWithToken(pattern, LockPatternUtils.CREDENTIAL_TYPE_PATTERN,
|
||||
handle, token, PASSWORD_QUALITY_SOMETHING, PRIMARY_USER_ID);
|
||||
|
||||
// Verify DPM gets notified about new device lock
|
||||
mService.mHandler.runWithScissors(() -> {}, 0 /*now*/); // Flush runnables on handler
|
||||
PasswordMetrics metric = PasswordMetrics.computeForPassword(PATTERN);
|
||||
PasswordMetrics metric = PasswordMetrics.computeForPassword(pattern);
|
||||
metric.quality = PASSWORD_QUALITY_SOMETHING;
|
||||
verify(mDevicePolicyManager).setActivePasswordState(metric, PRIMARY_USER_ID);
|
||||
|
||||
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
|
||||
PATTERN, LockPatternUtils.CREDENTIAL_TYPE_PATTERN, 0, PRIMARY_USER_ID)
|
||||
pattern, LockPatternUtils.CREDENTIAL_TYPE_PATTERN, 0, PRIMARY_USER_ID)
|
||||
.getResponseCode());
|
||||
assertArrayEquals(storageKey, mStorageManager.getUserUnlockToken(PRIMARY_USER_ID));
|
||||
}
|
||||
|
||||
public void testTokenBasedClearPassword() throws RemoteException {
|
||||
final String PASSWORD = "password";
|
||||
final String PATTERN = "123654";
|
||||
final String TOKEN = "some-high-entropy-secure-token";
|
||||
initializeCredentialUnderSP(PASSWORD, PRIMARY_USER_ID);
|
||||
final byte[] password = "password".getBytes();
|
||||
final byte[] pattern = "123654".getBytes();
|
||||
final byte[] token = "some-high-entropy-secure-token".getBytes();
|
||||
initializeCredentialUnderSP(password, PRIMARY_USER_ID);
|
||||
final byte[] storageKey = mStorageManager.getUserUnlockToken(PRIMARY_USER_ID);
|
||||
|
||||
long handle = mLocalService.addEscrowToken(TOKEN.getBytes(), PRIMARY_USER_ID);
|
||||
long handle = mLocalService.addEscrowToken(token, PRIMARY_USER_ID);
|
||||
assertFalse(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
|
||||
|
||||
mService.verifyCredential(PASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
|
||||
mService.verifyCredential(password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
|
||||
0, PRIMARY_USER_ID).getResponseCode();
|
||||
assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
|
||||
|
||||
mLocalService.setLockCredentialWithToken(null, LockPatternUtils.CREDENTIAL_TYPE_NONE,
|
||||
handle, TOKEN.getBytes(), PASSWORD_QUALITY_UNSPECIFIED, PRIMARY_USER_ID);
|
||||
mLocalService.setLockCredentialWithToken(PATTERN, LockPatternUtils.CREDENTIAL_TYPE_PATTERN,
|
||||
handle, TOKEN.getBytes(), PASSWORD_QUALITY_SOMETHING, PRIMARY_USER_ID);
|
||||
handle, token, PASSWORD_QUALITY_UNSPECIFIED, PRIMARY_USER_ID);
|
||||
mLocalService.setLockCredentialWithToken(pattern, LockPatternUtils.CREDENTIAL_TYPE_PATTERN,
|
||||
handle, token, PASSWORD_QUALITY_SOMETHING, PRIMARY_USER_ID);
|
||||
|
||||
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
|
||||
PATTERN, LockPatternUtils.CREDENTIAL_TYPE_PATTERN, 0, PRIMARY_USER_ID)
|
||||
pattern, LockPatternUtils.CREDENTIAL_TYPE_PATTERN, 0, PRIMARY_USER_ID)
|
||||
.getResponseCode());
|
||||
assertArrayEquals(storageKey, mStorageManager.getUserUnlockToken(PRIMARY_USER_ID));
|
||||
}
|
||||
|
||||
public void testTokenBasedResetPasswordAfterCredentialChanges() throws RemoteException {
|
||||
final String PASSWORD = "password";
|
||||
final String PATTERN = "123654";
|
||||
final String NEWPASSWORD = "password";
|
||||
final String TOKEN = "some-high-entropy-secure-token";
|
||||
initializeCredentialUnderSP(PASSWORD, PRIMARY_USER_ID);
|
||||
final byte[] password = "password".getBytes();
|
||||
final byte[] pattern = "123654".getBytes();
|
||||
final byte[] newPassword = "password".getBytes();
|
||||
final byte[] token = "some-high-entropy-secure-token".getBytes();
|
||||
initializeCredentialUnderSP(password, PRIMARY_USER_ID);
|
||||
final byte[] storageKey = mStorageManager.getUserUnlockToken(PRIMARY_USER_ID);
|
||||
|
||||
long handle = mLocalService.addEscrowToken(TOKEN.getBytes(), PRIMARY_USER_ID);
|
||||
long handle = mLocalService.addEscrowToken(token, PRIMARY_USER_ID);
|
||||
assertFalse(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
|
||||
|
||||
mService.verifyCredential(PASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
|
||||
mService.verifyCredential(password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
|
||||
0, PRIMARY_USER_ID).getResponseCode();
|
||||
assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
|
||||
|
||||
mService.setLockCredential(PATTERN, LockPatternUtils.CREDENTIAL_TYPE_PATTERN, PASSWORD,
|
||||
mService.setLockCredential(pattern, LockPatternUtils.CREDENTIAL_TYPE_PATTERN, password,
|
||||
PASSWORD_QUALITY_SOMETHING, PRIMARY_USER_ID);
|
||||
|
||||
mLocalService.setLockCredentialWithToken(NEWPASSWORD,
|
||||
LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, handle, TOKEN.getBytes(),
|
||||
mLocalService.setLockCredentialWithToken(newPassword,
|
||||
LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, handle, token,
|
||||
PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
|
||||
|
||||
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
|
||||
NEWPASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
|
||||
newPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
|
||||
.getResponseCode());
|
||||
assertArrayEquals(storageKey, mStorageManager.getUserUnlockToken(PRIMARY_USER_ID));
|
||||
}
|
||||
|
||||
public void testEscrowTokenActivatedImmediatelyIfNoUserPasswordNeedsMigration()
|
||||
throws RemoteException {
|
||||
final String TOKEN = "some-high-entropy-secure-token";
|
||||
final String token = "some-high-entropy-secure-token";
|
||||
enableSyntheticPassword();
|
||||
long handle = mLocalService.addEscrowToken(TOKEN.getBytes(), PRIMARY_USER_ID);
|
||||
long handle = mLocalService.addEscrowToken(token.getBytes(), PRIMARY_USER_ID);
|
||||
assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
|
||||
assertEquals(0, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
|
||||
assertTrue(hasSyntheticPassword(PRIMARY_USER_ID));
|
||||
@@ -419,9 +425,9 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests {
|
||||
|
||||
public void testEscrowTokenActivatedImmediatelyIfNoUserPasswordNoMigration()
|
||||
throws RemoteException {
|
||||
final String TOKEN = "some-high-entropy-secure-token";
|
||||
final String token = "some-high-entropy-secure-token";
|
||||
initializeCredentialUnderSP(null, PRIMARY_USER_ID);
|
||||
long handle = mLocalService.addEscrowToken(TOKEN.getBytes(), PRIMARY_USER_ID);
|
||||
long handle = mLocalService.addEscrowToken(token.getBytes(), PRIMARY_USER_ID);
|
||||
assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
|
||||
assertEquals(0, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
|
||||
assertTrue(hasSyntheticPassword(PRIMARY_USER_ID));
|
||||
@@ -429,34 +435,34 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests {
|
||||
|
||||
public void testEscrowTokenActivatedLaterWithUserPasswordNeedsMigration()
|
||||
throws RemoteException {
|
||||
final String TOKEN = "some-high-entropy-secure-token";
|
||||
final String PASSWORD = "password";
|
||||
final byte[] token = "some-high-entropy-secure-token".getBytes();
|
||||
final byte[] password = "password".getBytes();
|
||||
// Set up pre-SP user password
|
||||
disableSyntheticPassword();
|
||||
mService.setLockCredential(PASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
|
||||
mService.setLockCredential(password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
|
||||
PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
|
||||
enableSyntheticPassword();
|
||||
|
||||
long handle = mLocalService.addEscrowToken(TOKEN.getBytes(), PRIMARY_USER_ID);
|
||||
long handle = mLocalService.addEscrowToken(token, PRIMARY_USER_ID);
|
||||
// Token not activated immediately since user password exists
|
||||
assertFalse(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
|
||||
// Activate token (password gets migrated to SP at the same time)
|
||||
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
|
||||
PASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
|
||||
password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
|
||||
.getResponseCode());
|
||||
// Verify token is activated
|
||||
assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
|
||||
}
|
||||
|
||||
public void testgetHashFactorPrimaryUser() throws RemoteException {
|
||||
final String password = "password";
|
||||
final byte[] password = "password".getBytes();
|
||||
mService.setLockCredential(password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
|
||||
PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
|
||||
final byte[] hashFactor = mService.getHashFactor(password, PRIMARY_USER_ID);
|
||||
assertNotNull(hashFactor);
|
||||
|
||||
mService.setLockCredential(null, LockPatternUtils.CREDENTIAL_TYPE_NONE, password,
|
||||
PASSWORD_QUALITY_UNSPECIFIED, PRIMARY_USER_ID);
|
||||
mService.setLockCredential(null, LockPatternUtils.CREDENTIAL_TYPE_NONE,
|
||||
password, PASSWORD_QUALITY_UNSPECIFIED, PRIMARY_USER_ID);
|
||||
final byte[] newHashFactor = mService.getHashFactor(null, PRIMARY_USER_ID);
|
||||
assertNotNull(newHashFactor);
|
||||
// Hash factor should never change after password change/removal
|
||||
@@ -464,16 +470,16 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests {
|
||||
}
|
||||
|
||||
public void testgetHashFactorManagedProfileUnifiedChallenge() throws RemoteException {
|
||||
final String pattern = "1236";
|
||||
mService.setLockCredential(pattern, LockPatternUtils.CREDENTIAL_TYPE_PATTERN, null,
|
||||
PASSWORD_QUALITY_SOMETHING, PRIMARY_USER_ID);
|
||||
final byte[] pattern = "1236".getBytes();
|
||||
mService.setLockCredential(pattern, LockPatternUtils.CREDENTIAL_TYPE_PATTERN,
|
||||
null, PASSWORD_QUALITY_SOMETHING, PRIMARY_USER_ID);
|
||||
mService.setSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID, false, null);
|
||||
assertNotNull(mService.getHashFactor(null, MANAGED_PROFILE_USER_ID));
|
||||
}
|
||||
|
||||
public void testgetHashFactorManagedProfileSeparateChallenge() throws RemoteException {
|
||||
final String primaryPassword = "primary";
|
||||
final String profilePassword = "profile";
|
||||
final byte[] primaryPassword = "primary".getBytes();
|
||||
final byte[] profilePassword = "profile".getBytes();
|
||||
mService.setLockCredential(primaryPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
|
||||
PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
|
||||
mService.setLockCredential(profilePassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
|
||||
|
||||
@@ -135,7 +135,7 @@ public class KeySyncTaskTest {
|
||||
mSnapshotListenersStorage,
|
||||
TEST_USER_ID,
|
||||
TEST_CREDENTIAL_TYPE,
|
||||
TEST_CREDENTIAL,
|
||||
TEST_CREDENTIAL.getBytes(),
|
||||
/*credentialUpdated=*/ false,
|
||||
mPlatformKeyManager,
|
||||
mTestOnlyInsecureCertificateHelper,
|
||||
@@ -159,17 +159,17 @@ public class KeySyncTaskTest {
|
||||
|
||||
@Test
|
||||
public void isPin_isTrueForNumericString() {
|
||||
assertTrue(KeySyncTask.isPin("3298432574398654376547"));
|
||||
assertTrue(KeySyncTask.isPin("3298432574398654376547".getBytes()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isPin_isFalseForStringContainingLetters() {
|
||||
assertFalse(KeySyncTask.isPin("398i54369548654"));
|
||||
assertFalse(KeySyncTask.isPin("398i54369548654".getBytes()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isPin_isFalseForStringContainingSymbols() {
|
||||
assertFalse(KeySyncTask.isPin("-3987543643"));
|
||||
assertFalse(KeySyncTask.isPin("-3987543643".getBytes()));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -178,8 +178,8 @@ public class KeySyncTaskTest {
|
||||
byte[] salt = randomBytes(16);
|
||||
|
||||
assertArrayEquals(
|
||||
KeySyncTask.hashCredentialsBySaltedSha256(salt, credentials),
|
||||
KeySyncTask.hashCredentialsBySaltedSha256(salt, credentials));
|
||||
KeySyncTask.hashCredentialsBySaltedSha256(salt, credentials.getBytes()),
|
||||
KeySyncTask.hashCredentialsBySaltedSha256(salt, credentials.getBytes()));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -188,8 +188,8 @@ public class KeySyncTaskTest {
|
||||
|
||||
assertFalse(
|
||||
Arrays.equals(
|
||||
KeySyncTask.hashCredentialsBySaltedSha256(salt, "password1234"),
|
||||
KeySyncTask.hashCredentialsBySaltedSha256(salt, "password12345")));
|
||||
KeySyncTask.hashCredentialsBySaltedSha256(salt, "password1234".getBytes()),
|
||||
KeySyncTask.hashCredentialsBySaltedSha256(salt, "password12345".getBytes())));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -198,34 +198,38 @@ public class KeySyncTaskTest {
|
||||
|
||||
assertFalse(
|
||||
Arrays.equals(
|
||||
KeySyncTask.hashCredentialsBySaltedSha256(randomBytes(64), credentials),
|
||||
KeySyncTask.hashCredentialsBySaltedSha256(randomBytes(64), credentials)));
|
||||
KeySyncTask.hashCredentialsBySaltedSha256(randomBytes(64),
|
||||
credentials.getBytes()),
|
||||
KeySyncTask.hashCredentialsBySaltedSha256(randomBytes(64),
|
||||
credentials.getBytes())));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void hashCredentialsBySaltedSha256_returnsDifferentHashEvenIfConcatIsSame() {
|
||||
assertFalse(
|
||||
Arrays.equals(
|
||||
KeySyncTask.hashCredentialsBySaltedSha256(utf8Bytes("123"), "4567"),
|
||||
KeySyncTask.hashCredentialsBySaltedSha256(utf8Bytes("1234"), "567")));
|
||||
KeySyncTask.hashCredentialsBySaltedSha256(utf8Bytes("123"),
|
||||
"4567".getBytes()),
|
||||
KeySyncTask.hashCredentialsBySaltedSha256(utf8Bytes("1234"),
|
||||
"567".getBytes())));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getUiFormat_returnsPinIfPin() {
|
||||
assertEquals(UI_FORMAT_PIN,
|
||||
KeySyncTask.getUiFormat(CREDENTIAL_TYPE_PASSWORD, "1234"));
|
||||
KeySyncTask.getUiFormat(CREDENTIAL_TYPE_PASSWORD, "1234".getBytes()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getUiFormat_returnsPasswordIfPassword() {
|
||||
assertEquals(UI_FORMAT_PASSWORD,
|
||||
KeySyncTask.getUiFormat(CREDENTIAL_TYPE_PASSWORD, "1234a"));
|
||||
KeySyncTask.getUiFormat(CREDENTIAL_TYPE_PASSWORD, "1234a".getBytes()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getUiFormat_returnsPatternIfPattern() {
|
||||
assertEquals(UI_FORMAT_PATTERN,
|
||||
KeySyncTask.getUiFormat(CREDENTIAL_TYPE_PATTERN, "1234"));
|
||||
KeySyncTask.getUiFormat(CREDENTIAL_TYPE_PATTERN, "1234".getBytes()));
|
||||
|
||||
}
|
||||
|
||||
@@ -287,7 +291,7 @@ public class KeySyncTaskTest {
|
||||
mSnapshotListenersStorage,
|
||||
TEST_USER_ID,
|
||||
CREDENTIAL_TYPE_PASSWORD,
|
||||
/*credential=*/ password,
|
||||
/*credential=*/ password.getBytes(),
|
||||
/*credentialUpdated=*/ false,
|
||||
mPlatformKeyManager,
|
||||
mTestOnlyInsecureCertificateHelper,
|
||||
@@ -328,7 +332,7 @@ public class KeySyncTaskTest {
|
||||
mSnapshotListenersStorage,
|
||||
TEST_USER_ID,
|
||||
CREDENTIAL_TYPE_PATTERN,
|
||||
/*credential=*/ pattern,
|
||||
/*credential=*/ pattern.getBytes(),
|
||||
/*credentialUpdated=*/ false,
|
||||
mPlatformKeyManager,
|
||||
mTestOnlyInsecureCertificateHelper,
|
||||
@@ -362,7 +366,7 @@ public class KeySyncTaskTest {
|
||||
mSnapshotListenersStorage,
|
||||
TEST_USER_ID,
|
||||
CREDENTIAL_TYPE_PASSWORD,
|
||||
/*credential=*/ shortPassword,
|
||||
/*credential=*/ shortPassword.getBytes(),
|
||||
/*credentialUpdated=*/ false,
|
||||
mPlatformKeyManager,
|
||||
mTestOnlyInsecureCertificateHelper,
|
||||
@@ -522,7 +526,7 @@ public class KeySyncTaskTest {
|
||||
verify(mSnapshotListenersStorage).recoverySnapshotAvailable(TEST_RECOVERY_AGENT_UID);
|
||||
byte[] lockScreenHash = KeySyncTask.hashCredentialsBySaltedSha256(
|
||||
keyDerivationParams.getSalt(),
|
||||
TEST_CREDENTIAL);
|
||||
TEST_CREDENTIAL.getBytes());
|
||||
Long counterId = mRecoverableKeyStoreDb.getCounterId(TEST_USER_ID, TEST_RECOVERY_AGENT_UID);
|
||||
assertThat(counterId).isNotNull();
|
||||
byte[] recoveryKey = decryptThmEncryptedKey(
|
||||
@@ -616,7 +620,7 @@ public class KeySyncTaskTest {
|
||||
mSnapshotListenersStorage,
|
||||
TEST_USER_ID,
|
||||
CREDENTIAL_TYPE_PASSWORD,
|
||||
password,
|
||||
password.getBytes(),
|
||||
/*credentialUpdated=*/ false,
|
||||
mPlatformKeyManager,
|
||||
mTestOnlyInsecureCertificateHelper,
|
||||
@@ -647,7 +651,7 @@ public class KeySyncTaskTest {
|
||||
mSnapshotListenersStorage,
|
||||
TEST_USER_ID,
|
||||
CREDENTIAL_TYPE_PASSWORD,
|
||||
/*credential=*/ pin,
|
||||
/*credential=*/ pin.getBytes(),
|
||||
/*credentialUpdated=*/ false,
|
||||
mPlatformKeyManager,
|
||||
mTestOnlyInsecureCertificateHelper,
|
||||
@@ -679,7 +683,7 @@ public class KeySyncTaskTest {
|
||||
mSnapshotListenersStorage,
|
||||
TEST_USER_ID,
|
||||
CREDENTIAL_TYPE_PATTERN,
|
||||
"12345",
|
||||
"12345".getBytes(),
|
||||
/*credentialUpdated=*/ false,
|
||||
mPlatformKeyManager,
|
||||
mTestOnlyInsecureCertificateHelper,
|
||||
@@ -763,7 +767,7 @@ public class KeySyncTaskTest {
|
||||
mSnapshotListenersStorage,
|
||||
TEST_USER_ID,
|
||||
/*credentialType=*/ 3,
|
||||
"12345",
|
||||
"12345".getBytes(),
|
||||
/*credentialUpdated=*/ false,
|
||||
mPlatformKeyManager,
|
||||
mTestOnlyInsecureCertificateHelper,
|
||||
|
||||
@@ -24,30 +24,30 @@ public class TestOnlyInsecureCertificateHelperTest {
|
||||
@Test
|
||||
public void testDoesCredentailSupportInsecureMode_forNonWhitelistedPassword() throws Exception {
|
||||
assertThat(mHelper.doesCredentialSupportInsecureMode(
|
||||
LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, "secret12345")).isFalse();
|
||||
LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, "secret12345".getBytes())).isFalse();
|
||||
assertThat(mHelper.doesCredentialSupportInsecureMode(
|
||||
LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, "1234")).isFalse();
|
||||
LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, "1234".getBytes())).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDoesCredentailSupportInsecureMode_forWhitelistedPassword() throws Exception {
|
||||
assertThat(mHelper.doesCredentialSupportInsecureMode(
|
||||
LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
|
||||
TrustedRootCertificates.INSECURE_PASSWORD_PREFIX)).isTrue();
|
||||
TrustedRootCertificates.INSECURE_PASSWORD_PREFIX.getBytes())).isTrue();
|
||||
|
||||
assertThat(mHelper.doesCredentialSupportInsecureMode(
|
||||
LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
|
||||
TrustedRootCertificates.INSECURE_PASSWORD_PREFIX + "12")).isTrue();
|
||||
(TrustedRootCertificates.INSECURE_PASSWORD_PREFIX + "12").getBytes())).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDoesCredentailSupportInsecureMode_Pattern() throws Exception {
|
||||
assertThat(mHelper.doesCredentialSupportInsecureMode(
|
||||
LockPatternUtils.CREDENTIAL_TYPE_PATTERN,
|
||||
TrustedRootCertificates.INSECURE_PASSWORD_PREFIX)).isFalse();
|
||||
TrustedRootCertificates.INSECURE_PASSWORD_PREFIX.getBytes())).isFalse();
|
||||
assertThat(mHelper.doesCredentialSupportInsecureMode(
|
||||
LockPatternUtils.CREDENTIAL_TYPE_NONE,
|
||||
TrustedRootCertificates.INSECURE_PASSWORD_PREFIX)).isFalse();
|
||||
TrustedRootCertificates.INSECURE_PASSWORD_PREFIX.getBytes())).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Reference in New Issue
Block a user