From f64ec63a027447d8e38dd3e0d05d127cf06dccfc Mon Sep 17 00:00:00 2001 From: Rich Cannings Date: Thu, 21 Feb 2019 12:40:36 -0800 Subject: [PATCH] Refactor passwords/pins/patterns to byte[] Relating to frameworks/base Bug: 120484642 Test: manual - test setting and unlocking passwords/pins/patterns. automated - about 20 failing due to an issue in the test code. Change-Id: I57aa530ca2db1a026c56b66f5b4c91172f2667f6 --- .../android/app/admin/PasswordMetrics.java | 25 +- .../internal/widget/ILockSettings.aidl | 12 +- .../internal/widget/LockPatternChecker.java | 43 +++- .../internal/widget/LockPatternUtils.java | 216 +++++++++++++---- .../internal/widget/LockPatternView.java | 4 +- .../internal/widget/LockSettingsInternal.java | 6 +- .../app/admin/PasswordMetricsTest.java | 59 ++--- .../keyguard/KeyguardAbsKeyInputView.java | 12 +- .../keyguard/KeyguardPasswordView.java | 18 +- .../keyguard/KeyguardPinBasedInputView.java | 18 +- .../locksettings/LockSettingsService.java | 160 +++++++------ .../LockSettingsShellCommand.java | 19 +- .../SyntheticPasswordManager.java | 34 +-- .../recoverablekeystore/KeySyncTask.java | 29 +-- .../RecoverableKeyStoreManager.java | 10 +- .../TestOnlyInsecureCertificateHelper.java | 28 ++- .../DevicePolicyManagerService.java | 19 +- .../devicepolicy/DevicePolicyManagerTest.java | 8 +- .../CachedSyntheticPasswordTests.java | 73 +++--- .../LockSettingsServiceTestable.java | 8 +- .../LockSettingsServiceTests.java | 62 ++--- .../LockSettingsShellCommandTest.java | 22 +- .../MockSyntheticPasswordManager.java | 8 +- .../locksettings/SyntheticPasswordTests.java | 224 +++++++++--------- .../recoverablekeystore/KeySyncTaskTest.java | 50 ++-- ...TestOnlyInsecureCertificateHelperTest.java | 12 +- 26 files changed, 725 insertions(+), 454 deletions(-) diff --git a/core/java/android/app/admin/PasswordMetrics.java b/core/java/android/app/admin/PasswordMetrics.java index e5df2c70eeec..a6bf5012d9e5 100644 --- a/core/java/android/app/admin/PasswordMetrics.java +++ b/core/java/android/app/admin/PasswordMetrics.java @@ -221,7 +221,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; @@ -229,9 +232,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++; @@ -296,7 +299,7 @@ public class PasswordMetrics implements Parcelable { return false; } - /* + /** * 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. * @@ -310,19 +313,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)) { @@ -341,7 +344,7 @@ public class PasswordMetrics implements Parcelable { } previousChar = currentChar; } - maxLength = Math.max(maxLength, string.length() - startSequence); + maxLength = Math.max(maxLength, bytes.length - startSequence); return maxLength; } diff --git a/core/java/com/android/internal/widget/ILockSettings.aidl b/core/java/com/android/internal/widget/ILockSettings.aidl index 9a77802aa541..1c5816c1578e 100644 --- a/core/java/com/android/internal/widget/ILockSettings.aidl +++ b/core/java/com/android/internal/widget/ILockSettings.aidl @@ -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); diff --git a/core/java/com/android/internal/widget/LockPatternChecker.java b/core/java/com/android/internal/widget/LockPatternChecker.java index 586ece0a274a..bda3b5728fdc 100644 --- a/core/java/com/android/internal/widget/LockPatternChecker.java +++ b/core/java/com/android/internal/widget/LockPatternChecker.java @@ -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 task = new AsyncTask() { 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 task = new AsyncTask() { 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; diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java index 8d3c482104f7..17ed2a0a048c 100644 --- a/core/java/com/android/internal/widget/LockPatternUtils.java +++ b/core/java/com/android/internal/widget/LockPatternUtils.java @@ -67,6 +67,7 @@ import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.List; import java.util.StringJoiner; @@ -356,7 +357,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, @@ -373,7 +374,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 { @@ -404,7 +405,7 @@ public class LockPatternUtils { public byte[] verifyPattern(List 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); } @@ -429,7 +430,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); } @@ -442,7 +443,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); @@ -458,7 +459,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 { @@ -480,16 +481,31 @@ 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 { - return checkPassword(password, userId, null /* progressCallback */); + 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. @@ -498,6 +514,22 @@ public class LockPatternUtils { 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(byte[] password, int userId, + @Nullable CheckCredentialProgressCallback progressCallback) + throws RequestThrottledException { throwIfCalledOnMainThread(); return checkCredential(password, CREDENTIAL_TYPE_PASSWORD, userId, progressCallback); } @@ -519,7 +551,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) { @@ -537,8 +569,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; } @@ -639,13 +671,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); @@ -704,10 +736,11 @@ 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 pattern, String savedPattern, int userId) { + public void saveLockPattern(List pattern, byte[] savedPattern, + int userId) { if (!hasSecureLockScreen()) { throw new UnsupportedOperationException( "This operation requires the lock screen feature."); @@ -717,12 +750,12 @@ public class LockPatternUtils { + 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); @@ -734,7 +767,7 @@ public class LockPatternUtils { if (!shouldEncryptWithCredentials(true)) { clearEncryptionPassword(); } else { - updateEncryptionPassword(StorageManager.CRYPT_TYPE_PATTERN, stringPattern); + updateEncryptionPassword(StorageManager.CRYPT_TYPE_PATTERN, bytePattern); } } @@ -806,7 +839,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 (!hasSecureLockScreen()) { throw new UnsupportedOperationException( "This operation requires the lock screen feature."); @@ -825,7 +858,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); } @@ -842,14 +877,34 @@ 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) { + 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 (!hasSecureLockScreen()) { throw new UnsupportedOperationException( "This operation requires the lock screen feature."); } - if (password == null || password.length() < MIN_LOCK_PASSWORD_SIZE) { + 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); } @@ -864,8 +919,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); @@ -882,7 +937,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()) { @@ -902,8 +957,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; } @@ -982,7 +1037,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; @@ -1005,7 +1060,7 @@ public class LockPatternUtils { * true */ public void setSeparateProfileChallengeEnabled(int userHandle, boolean enabled, - String managedUserPassword) { + byte[] managedUserPassword) { if (!isManagedProfile(userHandle)) { return; } @@ -1069,15 +1124,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 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 byteArrayToPattern(byte[] bytes) { + if (bytes == null) { + return null; + } List 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)); @@ -1089,10 +1157,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 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 pattern) { if (pattern == null) { - return ""; + return new byte[0]; } final int patternSize = pattern.size(); @@ -1101,21 +1181,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; } /* @@ -1169,13 +1252,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); @@ -1184,6 +1272,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); @@ -1193,14 +1282,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); @@ -1633,7 +1727,7 @@ 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) { if (!hasSecureLockScreen()) { throw new UnsupportedOperationException( @@ -1641,13 +1735,13 @@ public class LockPatternUtils { } 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); @@ -1656,11 +1750,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); @@ -1891,4 +1985,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; + } } diff --git a/core/java/com/android/internal/widget/LockPatternView.java b/core/java/com/android/internal/widget/LockPatternView.java index 25a5a0734bf5..4b269901ccf6 100644 --- a/core/java/com/android/internal/widget/LockPatternView.java +++ b/core/java/com/android/internal/widget/LockPatternView.java @@ -1273,8 +1273,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); } diff --git a/core/java/com/android/internal/widget/LockSettingsInternal.java b/core/java/com/android/internal/widget/LockSettingsInternal.java index 9de9ef7f2aea..90397dffe5f9 100644 --- a/core/java/com/android/internal/widget/LockSettingsInternal.java +++ b/core/java/com/android/internal/widget/LockSettingsInternal.java @@ -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); diff --git a/core/tests/coretests/src/android/app/admin/PasswordMetricsTest.java b/core/tests/coretests/src/android/app/admin/PasswordMetricsTest.java index 5731daa0b2a9..4ae9494aa362 100644 --- a/core/tests/coretests/src/android/app/admin/PasswordMetricsTest.java +++ b/core/tests/coretests/src/android/app/admin/PasswordMetricsTest.java @@ -99,7 +99,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); @@ -112,32 +113,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(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 @@ -158,8 +159,8 @@ public class PasswordMetricsTest { assertNotEquals(new PasswordMetrics(DevicePolicyManager.PASSWORD_QUALITY_SOMETHING, 4), new PasswordMetrics(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); @@ -197,7 +198,7 @@ public class PasswordMetricsTest { @Test public void testDetermineComplexity_none() { assertEquals(PASSWORD_COMPLEXITY_NONE, - PasswordMetrics.computeForPassword("").determineComplexity()); + PasswordMetrics.computeForPassword("".getBytes()).determineComplexity()); } @Test @@ -209,61 +210,61 @@ public class PasswordMetricsTest { @Test public void testDetermineComplexity_lowNumeric() { assertEquals(PASSWORD_COMPLEXITY_LOW, - PasswordMetrics.computeForPassword("1234").determineComplexity()); + PasswordMetrics.computeForPassword("1234".getBytes()).determineComplexity()); } @Test public void testDetermineComplexity_lowNumericComplex() { assertEquals(PASSWORD_COMPLEXITY_LOW, - PasswordMetrics.computeForPassword("124").determineComplexity()); + PasswordMetrics.computeForPassword("124".getBytes()).determineComplexity()); } @Test public void testDetermineComplexity_lowAlphabetic() { assertEquals(PASSWORD_COMPLEXITY_LOW, - PasswordMetrics.computeForPassword("a!").determineComplexity()); + PasswordMetrics.computeForPassword("a!".getBytes()).determineComplexity()); } @Test public void testDetermineComplexity_lowAlphanumeric() { assertEquals(PASSWORD_COMPLEXITY_LOW, - PasswordMetrics.computeForPassword("a!1").determineComplexity()); + PasswordMetrics.computeForPassword("a!1".getBytes()).determineComplexity()); } @Test public void testDetermineComplexity_mediumNumericComplex() { assertEquals(PASSWORD_COMPLEXITY_MEDIUM, - PasswordMetrics.computeForPassword("1238").determineComplexity()); + PasswordMetrics.computeForPassword("1238".getBytes()).determineComplexity()); } @Test public void testDetermineComplexity_mediumAlphabetic() { assertEquals(PASSWORD_COMPLEXITY_MEDIUM, - PasswordMetrics.computeForPassword("ab!c").determineComplexity()); + PasswordMetrics.computeForPassword("ab!c".getBytes()).determineComplexity()); } @Test public void testDetermineComplexity_mediumAlphanumeric() { assertEquals(PASSWORD_COMPLEXITY_MEDIUM, - PasswordMetrics.computeForPassword("ab!1").determineComplexity()); + PasswordMetrics.computeForPassword("ab!1".getBytes()).determineComplexity()); } @Test public void testDetermineComplexity_highNumericComplex() { assertEquals(PASSWORD_COMPLEXITY_HIGH, - PasswordMetrics.computeForPassword("12389647!").determineComplexity()); + PasswordMetrics.computeForPassword("12389647!".getBytes()).determineComplexity()); } @Test public void testDetermineComplexity_highAlphabetic() { assertEquals(PASSWORD_COMPLEXITY_HIGH, - PasswordMetrics.computeForPassword("alphabetic!").determineComplexity()); + PasswordMetrics.computeForPassword("alphabetic!".getBytes()).determineComplexity()); } @Test public void testDetermineComplexity_highAlphanumeric() { - assertEquals(PASSWORD_COMPLEXITY_HIGH, - PasswordMetrics.computeForPassword("alphanumeric123!").determineComplexity()); + assertEquals(PASSWORD_COMPLEXITY_HIGH, PasswordMetrics.computeForPassword( + "alphanumeric123!".getBytes()).determineComplexity()); } @Test diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java index a055950a5522..4cb8d90927fd 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java @@ -34,6 +34,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. */ @@ -124,18 +126,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; } @@ -157,6 +160,7 @@ public abstract class KeyguardAbsKeyInputView extends LinearLayout } onPasswordChecked(userId, true /* matched */, 0 /* timeoutMs */, true /* isValidPassword */); + Arrays.fill(entry, (byte) 0); } @Override @@ -171,6 +175,7 @@ public abstract class KeyguardAbsKeyInputView extends LinearLayout onPasswordChecked(userId, false /* matched */, timeoutMs, true /* isValidPassword */); } + Arrays.fill(entry, (byte) 0); } @Override @@ -181,6 +186,7 @@ public abstract class KeyguardAbsKeyInputView extends LinearLayout LatencyTracker.getInstance(mContext).onActionEnd( ACTION_CHECK_CREDENTIAL_UNLOCKED); } + Arrays.fill(entry, (byte) 0); } }); } @@ -211,7 +217,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); diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java index 261f391839b3..185edbfa9856 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java @@ -241,8 +241,8 @@ public class KeyguardPasswordView extends KeyguardAbsKeyInputView } @Override - protected String getPasswordText() { - return mPasswordEntry.getText().toString(); + protected byte[] getPasswordText() { + return charSequenceToByteArray(mPasswordEntry.getText()); } @Override @@ -377,4 +377,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; + } } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java index 3cc18ddf3b2a..ecafc3408224 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java @@ -165,8 +165,8 @@ public abstract class KeyguardPinBasedInputView extends KeyguardAbsKeyInputView } @Override - protected String getPasswordText() { - return mPasswordEntry.getText(); + protected byte[] getPasswordText() { + return charSequenceToByteArray(mPasswordEntry.getText()); } @Override @@ -264,4 +264,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; + } } diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java index 924018ea3a5a..e1aa92c7bab8 100644 --- a/services/core/java/com/android/server/locksettings/LockSettingsService.java +++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java @@ -123,7 +123,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; @@ -277,7 +276,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()) { @@ -312,7 +311,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); @@ -321,6 +325,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 @@ -614,7 +619,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); @@ -952,7 +957,7 @@ public class LockSettingsService extends ILockSettings.Stub { @Override public void setSeparateProfileChallengeEnabled(int userId, boolean enabled, - String managedUserPassword) { + byte[] managedUserPassword) { checkWritePermission(userId); if (!mLockPatternUtils.hasSecureLockScreen()) { throw new UnsupportedOperationException( @@ -965,8 +970,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 { @@ -1109,24 +1114,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"); @@ -1145,7 +1154,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) @@ -1222,11 +1231,11 @@ public class LockSettingsService extends ILockSettings.Stub { && mUserManager.isUserRunning(userInfo.id); } - private Map getDecryptedPasswordsForAllTiedProfiles(int userId) { + private Map getDecryptedPasswordsForAllTiedProfiles(int userId) { if (mUserManager.getUserInfo(userId).isManagedProfile()) { return null; } - Map result = new ArrayMap(); + Map result = new ArrayMap(); final List profiles = mUserManager.getProfiles(userId); final int size = profiles.size(); for (int i = 0; i < size; i++) { @@ -1264,7 +1273,7 @@ public class LockSettingsService extends ILockSettings.Stub { * terminates when the user is a managed profile. */ private void synchronizeUnifiedWorkChallengeForProfiles(int userId, - Map profilePasswordMap) throws RemoteException { + Map profilePasswordMap) throws RemoteException { if (mUserManager.getUserInfo(userId).isManagedProfile()) { return; } @@ -1313,9 +1322,10 @@ 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 { + if (!mLockPatternUtils.hasSecureLockScreen()) { throw new UnsupportedOperationException( "This operation requires secure lock screen feature"); @@ -1329,14 +1339,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) { @@ -1405,7 +1415,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 @@ -1425,9 +1435,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 { @@ -1461,7 +1470,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. @@ -1486,17 +1495,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; @@ -1517,7 +1520,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) { @@ -1539,16 +1542,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"); @@ -1584,7 +1586,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 profiles = mUserManager.getProfiles(userId); for (UserInfo pi : profiles) { // Unlock managed profile with unified lock @@ -1621,17 +1623,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, @@ -1642,10 +1647,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(), @@ -1680,9 +1685,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; } @@ -1702,7 +1707,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)) { @@ -1744,14 +1749,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; } @@ -1762,14 +1768,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); } @@ -1800,7 +1806,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(); @@ -1859,7 +1865,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(); @@ -1908,6 +1914,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 { @@ -1922,8 +1929,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; } @@ -1933,8 +1940,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; } @@ -2318,7 +2325,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( @@ -2379,7 +2386,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); @@ -2478,12 +2485,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 profilePasswords; + final Map profilePasswords; if (credential != null) { // // not needed by synchronizeUnifiedWorkChallengeForProfiles() profilePasswords = null; @@ -2522,12 +2529,19 @@ public class LockSettingsService extends ILockSettings.Stub { synchronizeUnifiedWorkChallengeForProfiles(userId, profilePasswords); notifyActivePasswordMetricsAvailable(credential, userId); + + if (profilePasswords != null) { + for (Map.Entry 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 @@ -2600,9 +2614,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)) { @@ -2696,7 +2710,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) { @@ -2716,7 +2730,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) { @@ -2943,8 +2957,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) { if (!mLockPatternUtils.hasSecureLockScreen()) { throw new UnsupportedOperationException( "This operation requires secure lock screen feature."); diff --git a/services/core/java/com/android/server/locksettings/LockSettingsShellCommand.java b/services/core/java/com/android/server/locksettings/LockSettingsShellCommand.java index 6163077e1acf..ee22264112ab 100644 --- a/services/core/java/com/android/server/locksettings/LockSettingsShellCommand.java +++ b/services/core/java/com/android/server/locksettings/LockSettingsShellCommand.java @@ -190,22 +190,30 @@ class LockSettingsShellCommand extends ShellCommand { } private void runSetPattern() { - mLockPatternUtils.saveLockPattern(stringToPattern(mNew), mOld, mCurrentUserId); + byte[] oldBytes = mOld != null ? mOld.getBytes() : null; + mLockPatternUtils.saveLockPattern(stringToPattern(mNew), oldBytes, mCurrentUserId); getOutPrintWriter().println("Pattern set to '" + mNew + "'"); } private void runSetPassword() { - mLockPatternUtils.saveLockPassword(mNew, mOld, PASSWORD_QUALITY_ALPHABETIC, mCurrentUserId); + 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() { - mLockPatternUtils.saveLockPassword(mNew, mOld, PASSWORD_QUALITY_NUMERIC, mCurrentUserId); + 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() { - mLockPatternUtils.clearLock(mOld, mCurrentUserId); + byte[] oldBytes = mOld != null ? mOld.getBytes() : null; + mLockPatternUtils.clearLock(oldBytes, mCurrentUserId); getOutPrintWriter().println("Lock credential cleared"); } @@ -232,7 +240,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); } diff --git a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java index 0e195bcc98e0..ea39dff1acc9 100644 --- a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java +++ b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java @@ -97,7 +97,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; @@ -165,7 +165,7 @@ public class SyntheticPasswordManager { } } - public String deriveKeyStorePassword() { + public byte[] deriveKeyStorePassword() { return bytesToHex(derivePassword(PERSONALIZATION_KEY_STORE_PASSWORD)); } @@ -454,11 +454,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); @@ -616,7 +616,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) { @@ -670,7 +670,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) { @@ -839,7 +839,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; @@ -1152,7 +1152,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); } @@ -1173,8 +1173,8 @@ public class SyntheticPasswordManager { return nativeSidFromPasswordHandle(handle); } - protected byte[] scrypt(String password, byte[] salt, int N, int r, int p, int outLen) { - return new Scrypt().scrypt(password.getBytes(), salt, N, r, p, outLen); + protected byte[] scrypt(byte[] password, byte[] salt, int n, int r, int p, int outLen) { + return new Scrypt().scrypt(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; } } diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java index e7a71b99a213..5676da213dd2 100644 --- a/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java +++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java @@ -38,7 +38,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; @@ -51,6 +50,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; @@ -85,7 +85,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; @@ -100,7 +100,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( @@ -134,7 +134,7 @@ public class KeySyncTask implements Runnable { RecoverySnapshotListenersStorage recoverySnapshotListenersStorage, int userId, int credentialType, - String credential, + byte[] credential, boolean credentialUpdated, PlatformKeyManager platformKeyManager, TestOnlyInsecureCertificateHelper testOnlyInsecureCertificateHelper, @@ -450,7 +450,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)) { @@ -475,13 +475,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; } } @@ -494,8 +494,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); @@ -506,17 +505,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 { diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java index ed864c0221c9..47b9c27284e5 100644 --- a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java +++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java @@ -892,13 +892,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( @@ -923,13 +923,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 { diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/TestOnlyInsecureCertificateHelper.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/TestOnlyInsecureCertificateHelper.java index 057429c3e7d4..90a36723de4d 100644 --- a/services/core/java/com/android/server/locksettings/recoverablekeystore/TestOnlyInsecureCertificateHelper.java +++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/TestOnlyInsecureCertificateHelper.java @@ -87,10 +87,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> keepOnlyWhitelistedInsecureKeys( diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index ae48dad7b8f9..d773929c8628 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -5028,7 +5028,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) { @@ -5115,16 +5116,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) { diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java index de782a52eb53..4293247e7d0c 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java @@ -4167,7 +4167,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))) @@ -5214,7 +5214,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { .thenReturn(DpmMockContext.CALLER_USER_HANDLE); dpms.mUserPasswordMetrics.put( DpmMockContext.CALLER_USER_HANDLE, - PasswordMetrics.computeForPassword("asdf")); + PasswordMetrics.computeForPassword("asdf".getBytes())); assertEquals(PASSWORD_COMPLEXITY_MEDIUM, dpm.getPasswordComplexity()); } @@ -5231,10 +5231,10 @@ public class DevicePolicyManagerTest extends DpmTestBase { dpms.mUserPasswordMetrics.put( DpmMockContext.CALLER_USER_HANDLE, - PasswordMetrics.computeForPassword("asdf")); + PasswordMetrics.computeForPassword("asdf".getBytes())); dpms.mUserPasswordMetrics.put( parentUser.id, - PasswordMetrics.computeForPassword("parentUser")); + PasswordMetrics.computeForPassword("parentUser".getBytes())); assertEquals(PASSWORD_COMPLEXITY_HIGH, dpm.getPasswordComplexity()); } diff --git a/services/tests/servicestests/src/com/android/server/locksettings/CachedSyntheticPasswordTests.java b/services/tests/servicestests/src/com/android/server/locksettings/CachedSyntheticPasswordTests.java index d2caa0af0ba2..94d21ddeaa2b 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/CachedSyntheticPasswordTests.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/CachedSyntheticPasswordTests.java @@ -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> 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()); } diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java index 74d473944779..4f07d472a7aa 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java @@ -128,12 +128,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) { @@ -146,7 +146,7 @@ public class LockSettingsServiceTestable extends LockSettingsService { } catch (RemoteException e) { // shouldn't happen. } - return new String(storedData); + return storedData; } } diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java index 5124803ee298..6e0ba3cb366c 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java @@ -84,8 +84,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)); @@ -96,7 +96,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)); @@ -106,7 +106,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); @@ -125,8 +126,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)); @@ -141,15 +142,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)); @@ -158,14 +160,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); @@ -179,31 +183,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); } @@ -212,7 +217,8 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests { mHasSecureLockScreen = false; try { - mService.setLockCredential(credential, type, null, quality, userId); + mService.setLockCredential(credential.getBytes(), type, null, quality, + userId); fail("An exception should have been thrown."); } catch (UnsupportedOperationException e) { // Success - the exception was expected. @@ -226,15 +232,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)); @@ -253,18 +260,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 { diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsShellCommandTest.java b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsShellCommandTest.java index 929c3b525db9..fcfc6d2267c5 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsShellCommandTest.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsShellCommandTest.java @@ -85,23 +85,24 @@ 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 @@ -118,12 +119,12 @@ public class LockSettingsShellCommandTest { 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 @@ -144,7 +145,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 @@ -165,6 +167,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); } } diff --git a/services/tests/servicestests/src/com/android/server/locksettings/MockSyntheticPasswordManager.java b/services/tests/servicestests/src/com/android/server/locksettings/MockSyntheticPasswordManager.java index 6f681797b88a..b9cb730caae1 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/MockSyntheticPasswordManager.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/MockSyntheticPasswordManager.java @@ -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) { diff --git a/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java b/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java index 89e155ef0d8c..e6e020dbdb97 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java @@ -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,38 +435,38 @@ 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 testSetLockCredentialWithTokenFailsWithoutLockScreen() throws Exception { - final String password = "password"; - final String pattern = "123654"; - final String token = "some-high-entropy-secure-token"; + final byte[] password = "password".getBytes(); + final byte[] pattern = "123654".getBytes(); + final byte[] token = "some-high-entropy-secure-token".getBytes(); mHasSecureLockScreen = false; enableSyntheticPassword(); - long handle = mLocalService.addEscrowToken(token.getBytes(), PRIMARY_USER_ID); + long handle = mLocalService.addEscrowToken(token, PRIMARY_USER_ID); assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID)); try { mLocalService.setLockCredentialWithToken(password, - LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, handle, token.getBytes(), + LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, handle, token, PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID); fail("An exception should have been thrown."); } catch (UnsupportedOperationException e) { @@ -470,7 +476,7 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { try { mLocalService.setLockCredentialWithToken(pattern, - LockPatternUtils.CREDENTIAL_TYPE_PATTERN, handle, token.getBytes(), + LockPatternUtils.CREDENTIAL_TYPE_PATTERN, handle, token, PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID); fail("An exception should have been thrown."); } catch (UnsupportedOperationException e) { @@ -480,14 +486,14 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { } 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 @@ -495,16 +501,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, @@ -557,7 +563,7 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { public void testGsiDisablesAuthSecret() throws RemoteException { mGsiService.setIsGsiRunning(true); - final String password = "testGsiDisablesAuthSecret-password"; + final byte[] password = "testGsiDisablesAuthSecret-password".getBytes(); initializeCredentialUnderSP(password, PRIMARY_USER_ID); assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential( diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java index c2d4846b14c0..a992dd126f5d 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java @@ -139,7 +139,7 @@ public class KeySyncTaskTest { mSnapshotListenersStorage, TEST_USER_ID, TEST_CREDENTIAL_TYPE, - TEST_CREDENTIAL, + TEST_CREDENTIAL.getBytes(), /*credentialUpdated=*/ false, mPlatformKeyManager, mTestOnlyInsecureCertificateHelper, @@ -163,17 +163,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 @@ -182,8 +182,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 @@ -192,8 +192,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 @@ -202,34 +202,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())); } @@ -291,7 +295,7 @@ public class KeySyncTaskTest { mSnapshotListenersStorage, TEST_USER_ID, CREDENTIAL_TYPE_PASSWORD, - /*credential=*/ password, + /*credential=*/ password.getBytes(), /*credentialUpdated=*/ false, mPlatformKeyManager, mTestOnlyInsecureCertificateHelper, @@ -332,7 +336,7 @@ public class KeySyncTaskTest { mSnapshotListenersStorage, TEST_USER_ID, CREDENTIAL_TYPE_PATTERN, - /*credential=*/ pattern, + /*credential=*/ pattern.getBytes(), /*credentialUpdated=*/ false, mPlatformKeyManager, mTestOnlyInsecureCertificateHelper, @@ -366,7 +370,7 @@ public class KeySyncTaskTest { mSnapshotListenersStorage, TEST_USER_ID, CREDENTIAL_TYPE_PASSWORD, - /*credential=*/ shortPassword, + /*credential=*/ shortPassword.getBytes(), /*credentialUpdated=*/ false, mPlatformKeyManager, mTestOnlyInsecureCertificateHelper, @@ -526,7 +530,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( @@ -649,7 +653,7 @@ public class KeySyncTaskTest { mSnapshotListenersStorage, TEST_USER_ID, CREDENTIAL_TYPE_PASSWORD, - password, + password.getBytes(), /*credentialUpdated=*/ false, mPlatformKeyManager, mTestOnlyInsecureCertificateHelper, @@ -680,7 +684,7 @@ public class KeySyncTaskTest { mSnapshotListenersStorage, TEST_USER_ID, CREDENTIAL_TYPE_PASSWORD, - /*credential=*/ pin, + /*credential=*/ pin.getBytes(), /*credentialUpdated=*/ false, mPlatformKeyManager, mTestOnlyInsecureCertificateHelper, @@ -712,7 +716,7 @@ public class KeySyncTaskTest { mSnapshotListenersStorage, TEST_USER_ID, CREDENTIAL_TYPE_PATTERN, - "12345", + "12345".getBytes(), /*credentialUpdated=*/ false, mPlatformKeyManager, mTestOnlyInsecureCertificateHelper, @@ -796,7 +800,7 @@ public class KeySyncTaskTest { mSnapshotListenersStorage, TEST_USER_ID, /*credentialType=*/ 3, - "12345", + "12345".getBytes(), /*credentialUpdated=*/ false, mPlatformKeyManager, mTestOnlyInsecureCertificateHelper, diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/TestOnlyInsecureCertificateHelperTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/TestOnlyInsecureCertificateHelperTest.java index 9b4c3beac582..6921bb27ceb2 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/TestOnlyInsecureCertificateHelperTest.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/TestOnlyInsecureCertificateHelperTest.java @@ -27,30 +27,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 -- GitLab