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