Loading core/java/com/android/internal/widget/LockPatternUtils.java +57 −206 Original line number Diff line number Diff line Loading @@ -30,7 +30,6 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UnsupportedAppUsage; import android.app.admin.DevicePolicyManager; import android.app.admin.PasswordMetrics; import android.app.trust.IStrongAuthTracker; import android.app.trust.TrustManager; import android.content.ComponentName; Loading Loading @@ -598,44 +597,6 @@ public class LockPatternUtils { } } /** * Clear any lock pattern or password, with the option to ignore incorrect existing credential. * * <p> This method will fail (returning {@code false}) if the previously * saved password provided is incorrect, or if the lockscreen verification * is still being throttled. * * @param savedCredential The previously saved credential * @param userHandle the user whose pattern is to be saved. * @return whether this was successful or not. * @throws RuntimeException if password change encountered an unrecoverable error. */ private boolean clearLock(LockscreenCredential savedCredential, int userHandle, boolean allowUntrustedChange) { final int currentQuality = getKeyguardStoredPasswordQuality(userHandle); setKeyguardStoredPasswordQuality(PASSWORD_QUALITY_UNSPECIFIED, userHandle); try { if (!getLockSettings().setLockCredential(null, CREDENTIAL_TYPE_NONE, savedCredential.getCredential(), PASSWORD_QUALITY_UNSPECIFIED, userHandle, allowUntrustedChange)) { return false; } } catch (RemoteException | RuntimeException e) { setKeyguardStoredPasswordQuality(currentQuality, userHandle); throw new RuntimeException("Failed to clear lock", e); } if (userHandle == UserHandle.USER_SYSTEM) { // Set the encryption password to default. updateEncryptionPassword(StorageManager.CRYPT_TYPE_DEFAULT, null); setCredentialRequiredToDecrypt(false); } onAfterChangingPassword(userHandle); return true; } /** * Disable showing lock screen at all for a given user. * This is only meaningful if pattern, pin or password are not set. Loading Loading @@ -705,7 +666,7 @@ public class LockPatternUtils { * being throttled. * @param newCredential The new credential to save * @param savedCredential The current credential * @param userId the user whose lockscreen credential is to be changed * @param userHandle the user whose lockscreen credential is to be changed * @param allowUntrustedChange whether we want to allow saving a new pattern if the existing * credentialt being provided is incorrect. * Loading @@ -714,73 +675,43 @@ public class LockPatternUtils { * @throws RuntimeException if password change encountered an unrecoverable error. */ public boolean setLockCredential(@NonNull LockscreenCredential newCredential, @NonNull LockscreenCredential savedCredential, int userId, @NonNull LockscreenCredential savedCredential, int userHandle, boolean allowUntrustedChange) { if (newCredential.isNone()) { return clearLock(savedCredential, userId, allowUntrustedChange); } else if (newCredential.isPattern()) { return saveLockPattern(newCredential, savedCredential, userId, allowUntrustedChange); } else { return saveLockPassword(newCredential, savedCredential, newCredential.getQuality(), userId, allowUntrustedChange); } } /** * Save a lock pattern. * * <p> This method will fail (returning {@code false}) if the previously saved pattern provided * is incorrect, or if the lockscreen verification is still being throttled. * * @param pattern The new pattern to save. * @param savedCredential The previously saved credential * @param userId the user whose pattern is to be saved. * @param allowUntrustedChange whether we want to allow saving a new pattern if the existing * credentialt being provided is incorrect. * * @return whether this was successful or not. * @throws RuntimeException if password change encountered an unrecoverable error. */ private boolean saveLockPattern(LockscreenCredential pattern, LockscreenCredential savedCredential, int userId, boolean allowUntrustedChange) { if (!hasSecureLockScreen()) { throw new UnsupportedOperationException( "This operation requires the lock screen feature."); } 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."); } newCredential.checkLength(); final int currentQuality = getKeyguardStoredPasswordQuality(userHandle); setKeyguardStoredPasswordQuality(newCredential.getQuality(), userHandle); final int currentQuality = getKeyguardStoredPasswordQuality(userId); setKeyguardStoredPasswordQuality(PASSWORD_QUALITY_SOMETHING, userId); try { if (!getLockSettings().setLockCredential(pattern.getCredential(), pattern.getType(), savedCredential.getCredential(), PASSWORD_QUALITY_SOMETHING, userId, allowUntrustedChange)) { if (!getLockSettings().setLockCredential( newCredential.getCredential(), newCredential.getType(), savedCredential.getCredential(), newCredential.getQuality(), userHandle, allowUntrustedChange)) { setKeyguardStoredPasswordQuality(currentQuality, userHandle); return false; } } catch (RemoteException | RuntimeException e) { setKeyguardStoredPasswordQuality(currentQuality, userId); throw new RuntimeException("Couldn't save lock pattern", e); } // Update the device encryption password. if (userId == UserHandle.USER_SYSTEM && LockPatternUtils.isDeviceEncryptionEnabled()) { if (!shouldEncryptWithCredentials(true)) { clearEncryptionPassword(); } else { updateEncryptionPassword(StorageManager.CRYPT_TYPE_PATTERN, pattern.getCredential()); } setKeyguardStoredPasswordQuality(currentQuality, userHandle); throw new RuntimeException("Unable to save lock password", e); } reportPatternWasChosen(userId); onAfterChangingPassword(userId); onPostPasswordChanged(newCredential, userHandle); return true; } private void onPostPasswordChanged(LockscreenCredential newCredential, int userHandle) { updateEncryptionPasswordIfNeeded(newCredential, userHandle); if (newCredential.isPattern()) { reportPatternWasChosen(userHandle); } updatePasswordHistory(newCredential, userHandle); reportEnabledTrustAgentsChanged(userHandle); } private void updateCryptoUserInfo(int userId) { if (userId != UserHandle.USER_SYSTEM) { return; Loading Loading @@ -878,93 +809,24 @@ public class LockPatternUtils { }.execute(); } /** * Save a lock password. * * <p> This method will fail (returning {@code false}) if the previously saved password provided * is incorrect and allowUntrustedChange is false, or if the lockscreen verification * is still being throttled. * * @param password The password to save * @param savedCredential The previously saved lock credential * @param requestedQuality {@link DevicePolicyManager#getPasswordQuality( * android.content.ComponentName)} * @param userHandle The userId of the user to change the password for * @param allowUntrustedChange whether we want to allow saving a new password if the existing * password being provided is incorrect. * @return whether this method saved the new password successfully or not. This flow will fail * and return false if the given credential is wrong and allowUntrustedChange is false. * @throws RuntimeException if password change encountered an unrecoverable error. */ private boolean saveLockPassword(LockscreenCredential password, LockscreenCredential savedCredential, int requestedQuality, int userHandle, boolean allowUntrustedChange) { if (!hasSecureLockScreen()) { throw new UnsupportedOperationException( "This operation requires the lock screen feature."); } if (password.isNone() || password.size() < MIN_LOCK_PASSWORD_SIZE) { throw new IllegalArgumentException("password must not be null and at least " + "of length " + MIN_LOCK_PASSWORD_SIZE); } if (requestedQuality < PASSWORD_QUALITY_NUMERIC) { throw new IllegalArgumentException("quality must be at least NUMERIC, but was " + requestedQuality); } final int currentQuality = getKeyguardStoredPasswordQuality(userHandle); final int passwordQuality = PasswordMetrics.computeForPassword(password.getCredential()).quality; final int newKeyguardQuality = computeKeyguardQuality(CREDENTIAL_TYPE_PASSWORD, requestedQuality, passwordQuality); setKeyguardStoredPasswordQuality(newKeyguardQuality, userHandle); try { getLockSettings().setLockCredential(password.getCredential(), password.getType(), savedCredential.getCredential(), requestedQuality, userHandle, allowUntrustedChange); } catch (RemoteException | RuntimeException e) { setKeyguardStoredPasswordQuality(currentQuality, userHandle); throw new RuntimeException("Unable to save lock password", e); } updateEncryptionPasswordIfNeeded(password.getCredential(), passwordQuality, userHandle); updatePasswordHistory(password, userHandle); onAfterChangingPassword(userHandle); return true; } /** * Compute keyguard credential quality to store in PASSWORD_TYPE_KEY by computing max between * them so that digit-only password is distinguished from PIN. * * TODO: remove this method and make CREDENTIAL_TYPE distinguish between PIN and password, so * that this quality is no longer needs to be persisted. */ private int computeKeyguardQuality( @CredentialType int credentialType, int requestedQuality, int passwordQuality) { return credentialType == CREDENTIAL_TYPE_PASSWORD ? Math.max(passwordQuality, requestedQuality) : passwordQuality; } /** * Update device encryption password if calling user is USER_SYSTEM and device supports * encryption. */ private void updateEncryptionPasswordIfNeeded(byte[] password, int quality, int userHandle) { private void updateEncryptionPasswordIfNeeded(LockscreenCredential credential, int userHandle) { // Update the device encryption password. if (userHandle == UserHandle.USER_SYSTEM && LockPatternUtils.isDeviceEncryptionEnabled()) { if (userHandle != UserHandle.USER_SYSTEM || !isDeviceEncryptionEnabled()) { return; } if (!shouldEncryptWithCredentials(true)) { clearEncryptionPassword(); } else { boolean numeric = quality == PASSWORD_QUALITY_NUMERIC; boolean numericComplex = quality == PASSWORD_QUALITY_NUMERIC_COMPLEX; int type = numeric || numericComplex ? StorageManager.CRYPT_TYPE_PIN : StorageManager.CRYPT_TYPE_PASSWORD; updateEncryptionPassword(type, password); updateEncryptionPassword(StorageManager.CRYPT_TYPE_DEFAULT, null); return; } if (credential.isNone()) { // Set the encryption password to default. setCredentialRequiredToDecrypt(false); } updateEncryptionPassword(credential.getStorageCryptType(), credential.getCredential()); } /** Loading @@ -973,7 +835,10 @@ public class LockPatternUtils { */ private void updatePasswordHistory(LockscreenCredential password, int userHandle) { if (password.isNone()) { Log.e(TAG, "checkPasswordHistory: empty password"); return; } if (password.isPattern()) { // Do not keep track of historical patterns return; } // Add the password to the password history. We assume all Loading Loading @@ -1065,7 +930,7 @@ public class LockPatternUtils { try { getLockSettings().setSeparateProfileChallengeEnabled(userHandle, enabled, managedUserPassword.getCredential()); onAfterChangingPassword(userHandle); reportEnabledTrustAgentsChanged(userHandle); } catch (RemoteException e) { Log.e(TAG, "Couldn't update work profile challenge enabled"); } Loading Loading @@ -1506,7 +1371,7 @@ public class LockPatternUtils { } } private void onAfterChangingPassword(int userHandle) { private void reportEnabledTrustAgentsChanged(int userHandle) { getTrustManager().reportEnabledTrustAgentsChanged(userHandle); } Loading Loading @@ -1674,48 +1539,34 @@ public class LockPatternUtils { * @param credential The new credential to be set * @param tokenHandle Handle of the escrow token * @param token Escrow token * @param userId The user who's lock credential to be changed * @param userHandle The user who's lock credential to be changed * @return {@code true} if the operation is successful. */ public boolean setLockCredentialWithToken(LockscreenCredential credential, long tokenHandle, byte[] token, int userId) { byte[] token, int userHandle) { if (!hasSecureLockScreen()) { throw new UnsupportedOperationException( "This operation requires the lock screen feature."); } credential.checkLength(); LockSettingsInternal localService = getLockSettingsInternal(); if (!credential.isNone()) { if (credential.size() < MIN_LOCK_PASSWORD_SIZE) { throw new IllegalArgumentException("password must not be null and at least " + "of length " + MIN_LOCK_PASSWORD_SIZE); } final int type = credential.getType(); final int quality = PasswordMetrics.computeForCredential(credential).quality; final int keyguardQuality = computeKeyguardQuality(type, quality, credential.getQuality()); if (!localService.setLockCredentialWithToken(credential.getCredential(), type, tokenHandle, token, keyguardQuality, userId)) { return false; } setKeyguardStoredPasswordQuality(quality, userId); updateEncryptionPasswordIfNeeded(credential.getCredential(), quality, userId); updatePasswordHistory(credential, userId); onAfterChangingPassword(userId); } else { if (!localService.setLockCredentialWithToken(null, CREDENTIAL_TYPE_NONE, tokenHandle, token, PASSWORD_QUALITY_UNSPECIFIED, userId)) { return false; } setKeyguardStoredPasswordQuality(PASSWORD_QUALITY_UNSPECIFIED, userId); final int currentQuality = getKeyguardStoredPasswordQuality(userHandle); setKeyguardStoredPasswordQuality(credential.getQuality(), userHandle); if (userId == UserHandle.USER_SYSTEM) { // Set the encryption password to default. updateEncryptionPassword(StorageManager.CRYPT_TYPE_DEFAULT, null); setCredentialRequiredToDecrypt(false); try { if (!localService.setLockCredentialWithToken(credential.getCredential(), credential.getType(), tokenHandle, token, credential.getType(), userHandle)) { setKeyguardStoredPasswordQuality(currentQuality, userHandle); return false; } } catch (RuntimeException e) { setKeyguardStoredPasswordQuality(currentQuality, userHandle); throw new RuntimeException("Unable to save lock credential", e); } onAfterChangingPassword(userId); onPostPasswordChanged(credential, userHandle); return true; } Loading core/java/com/android/internal/widget/LockscreenCredential.java +45 −0 Original line number Diff line number Diff line Loading @@ -29,6 +29,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.os.Parcel; import android.os.Parcelable; import android.os.storage.StorageManager; import android.text.TextUtils; import com.android.internal.util.Preconditions; Loading Loading @@ -187,6 +188,25 @@ public class LockscreenCredential implements Parcelable, AutoCloseable { return mCredential; } /** * Returns the credential type recognized by {@link StorageManager}. Can be one of * {@link StorageManager#CRYPT_TYPE_DEFAULT}, {@link StorageManager#CRYPT_TYPE_PATTERN}, * {@link StorageManager#CRYPT_TYPE_PIN} or {@link StorageManager#CRYPT_TYPE_PASSWORD}. */ public int getStorageCryptType() { if (isNone()) { return StorageManager.CRYPT_TYPE_DEFAULT; } if (isPattern()) { return StorageManager.CRYPT_TYPE_PATTERN; } if (isPassword()) { return mQuality == PASSWORD_QUALITY_NUMERIC ? StorageManager.CRYPT_TYPE_PIN : StorageManager.CRYPT_TYPE_PASSWORD; } throw new IllegalStateException("Unhandled credential type"); } /** Returns whether this is an empty credential */ public boolean isNone() { ensureNotZeroized(); Loading Loading @@ -227,6 +247,31 @@ public class LockscreenCredential implements Parcelable, AutoCloseable { } } /** * Check if the credential meets minimal length requirement. * * @throws IllegalArgumentException if the credential is too short. */ public void checkLength() { if (isNone()) { return; } if (isPattern()) { if (size() < LockPatternUtils.MIN_LOCK_PATTERN_SIZE) { throw new IllegalArgumentException("pattern must not be null and at least " + LockPatternUtils.MIN_LOCK_PATTERN_SIZE + " dots long."); } return; } if (isPassword()) { if (size() < LockPatternUtils.MIN_LOCK_PASSWORD_SIZE) { throw new IllegalArgumentException("password must not be null and at least " + "of length " + LockPatternUtils.MIN_LOCK_PASSWORD_SIZE); } return; } } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeInt(mType); Loading services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java +3 −3 Original line number Diff line number Diff line Loading @@ -513,7 +513,7 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { assertFalse(mService.havePattern(PRIMARY_USER_ID)); } public void testgetHashFactorPrimaryUser() throws RemoteException { public void testGetHashFactorPrimaryUser() throws RemoteException { final byte[] password = "password".getBytes(); mService.setLockCredential(password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null, PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID, false); Loading @@ -528,7 +528,7 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { assertArrayEquals(hashFactor, newHashFactor); } public void testgetHashFactorManagedProfileUnifiedChallenge() throws RemoteException { public void testGetHashFactorManagedProfileUnifiedChallenge() throws RemoteException { final byte[] pattern = "1236".getBytes(); mService.setLockCredential(pattern, LockPatternUtils.CREDENTIAL_TYPE_PATTERN, null, PASSWORD_QUALITY_SOMETHING, PRIMARY_USER_ID, false); Loading @@ -536,7 +536,7 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { assertNotNull(mService.getHashFactor(null, MANAGED_PROFILE_USER_ID)); } public void testgetHashFactorManagedProfileSeparateChallenge() throws RemoteException { public void testGetHashFactorManagedProfileSeparateChallenge() throws RemoteException { final byte[] primaryPassword = "primary".getBytes(); final byte[] profilePassword = "profile".getBytes(); mService.setLockCredential(primaryPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null, Loading Loading
core/java/com/android/internal/widget/LockPatternUtils.java +57 −206 Original line number Diff line number Diff line Loading @@ -30,7 +30,6 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UnsupportedAppUsage; import android.app.admin.DevicePolicyManager; import android.app.admin.PasswordMetrics; import android.app.trust.IStrongAuthTracker; import android.app.trust.TrustManager; import android.content.ComponentName; Loading Loading @@ -598,44 +597,6 @@ public class LockPatternUtils { } } /** * Clear any lock pattern or password, with the option to ignore incorrect existing credential. * * <p> This method will fail (returning {@code false}) if the previously * saved password provided is incorrect, or if the lockscreen verification * is still being throttled. * * @param savedCredential The previously saved credential * @param userHandle the user whose pattern is to be saved. * @return whether this was successful or not. * @throws RuntimeException if password change encountered an unrecoverable error. */ private boolean clearLock(LockscreenCredential savedCredential, int userHandle, boolean allowUntrustedChange) { final int currentQuality = getKeyguardStoredPasswordQuality(userHandle); setKeyguardStoredPasswordQuality(PASSWORD_QUALITY_UNSPECIFIED, userHandle); try { if (!getLockSettings().setLockCredential(null, CREDENTIAL_TYPE_NONE, savedCredential.getCredential(), PASSWORD_QUALITY_UNSPECIFIED, userHandle, allowUntrustedChange)) { return false; } } catch (RemoteException | RuntimeException e) { setKeyguardStoredPasswordQuality(currentQuality, userHandle); throw new RuntimeException("Failed to clear lock", e); } if (userHandle == UserHandle.USER_SYSTEM) { // Set the encryption password to default. updateEncryptionPassword(StorageManager.CRYPT_TYPE_DEFAULT, null); setCredentialRequiredToDecrypt(false); } onAfterChangingPassword(userHandle); return true; } /** * Disable showing lock screen at all for a given user. * This is only meaningful if pattern, pin or password are not set. Loading Loading @@ -705,7 +666,7 @@ public class LockPatternUtils { * being throttled. * @param newCredential The new credential to save * @param savedCredential The current credential * @param userId the user whose lockscreen credential is to be changed * @param userHandle the user whose lockscreen credential is to be changed * @param allowUntrustedChange whether we want to allow saving a new pattern if the existing * credentialt being provided is incorrect. * Loading @@ -714,73 +675,43 @@ public class LockPatternUtils { * @throws RuntimeException if password change encountered an unrecoverable error. */ public boolean setLockCredential(@NonNull LockscreenCredential newCredential, @NonNull LockscreenCredential savedCredential, int userId, @NonNull LockscreenCredential savedCredential, int userHandle, boolean allowUntrustedChange) { if (newCredential.isNone()) { return clearLock(savedCredential, userId, allowUntrustedChange); } else if (newCredential.isPattern()) { return saveLockPattern(newCredential, savedCredential, userId, allowUntrustedChange); } else { return saveLockPassword(newCredential, savedCredential, newCredential.getQuality(), userId, allowUntrustedChange); } } /** * Save a lock pattern. * * <p> This method will fail (returning {@code false}) if the previously saved pattern provided * is incorrect, or if the lockscreen verification is still being throttled. * * @param pattern The new pattern to save. * @param savedCredential The previously saved credential * @param userId the user whose pattern is to be saved. * @param allowUntrustedChange whether we want to allow saving a new pattern if the existing * credentialt being provided is incorrect. * * @return whether this was successful or not. * @throws RuntimeException if password change encountered an unrecoverable error. */ private boolean saveLockPattern(LockscreenCredential pattern, LockscreenCredential savedCredential, int userId, boolean allowUntrustedChange) { if (!hasSecureLockScreen()) { throw new UnsupportedOperationException( "This operation requires the lock screen feature."); } 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."); } newCredential.checkLength(); final int currentQuality = getKeyguardStoredPasswordQuality(userHandle); setKeyguardStoredPasswordQuality(newCredential.getQuality(), userHandle); final int currentQuality = getKeyguardStoredPasswordQuality(userId); setKeyguardStoredPasswordQuality(PASSWORD_QUALITY_SOMETHING, userId); try { if (!getLockSettings().setLockCredential(pattern.getCredential(), pattern.getType(), savedCredential.getCredential(), PASSWORD_QUALITY_SOMETHING, userId, allowUntrustedChange)) { if (!getLockSettings().setLockCredential( newCredential.getCredential(), newCredential.getType(), savedCredential.getCredential(), newCredential.getQuality(), userHandle, allowUntrustedChange)) { setKeyguardStoredPasswordQuality(currentQuality, userHandle); return false; } } catch (RemoteException | RuntimeException e) { setKeyguardStoredPasswordQuality(currentQuality, userId); throw new RuntimeException("Couldn't save lock pattern", e); } // Update the device encryption password. if (userId == UserHandle.USER_SYSTEM && LockPatternUtils.isDeviceEncryptionEnabled()) { if (!shouldEncryptWithCredentials(true)) { clearEncryptionPassword(); } else { updateEncryptionPassword(StorageManager.CRYPT_TYPE_PATTERN, pattern.getCredential()); } setKeyguardStoredPasswordQuality(currentQuality, userHandle); throw new RuntimeException("Unable to save lock password", e); } reportPatternWasChosen(userId); onAfterChangingPassword(userId); onPostPasswordChanged(newCredential, userHandle); return true; } private void onPostPasswordChanged(LockscreenCredential newCredential, int userHandle) { updateEncryptionPasswordIfNeeded(newCredential, userHandle); if (newCredential.isPattern()) { reportPatternWasChosen(userHandle); } updatePasswordHistory(newCredential, userHandle); reportEnabledTrustAgentsChanged(userHandle); } private void updateCryptoUserInfo(int userId) { if (userId != UserHandle.USER_SYSTEM) { return; Loading Loading @@ -878,93 +809,24 @@ public class LockPatternUtils { }.execute(); } /** * Save a lock password. * * <p> This method will fail (returning {@code false}) if the previously saved password provided * is incorrect and allowUntrustedChange is false, or if the lockscreen verification * is still being throttled. * * @param password The password to save * @param savedCredential The previously saved lock credential * @param requestedQuality {@link DevicePolicyManager#getPasswordQuality( * android.content.ComponentName)} * @param userHandle The userId of the user to change the password for * @param allowUntrustedChange whether we want to allow saving a new password if the existing * password being provided is incorrect. * @return whether this method saved the new password successfully or not. This flow will fail * and return false if the given credential is wrong and allowUntrustedChange is false. * @throws RuntimeException if password change encountered an unrecoverable error. */ private boolean saveLockPassword(LockscreenCredential password, LockscreenCredential savedCredential, int requestedQuality, int userHandle, boolean allowUntrustedChange) { if (!hasSecureLockScreen()) { throw new UnsupportedOperationException( "This operation requires the lock screen feature."); } if (password.isNone() || password.size() < MIN_LOCK_PASSWORD_SIZE) { throw new IllegalArgumentException("password must not be null and at least " + "of length " + MIN_LOCK_PASSWORD_SIZE); } if (requestedQuality < PASSWORD_QUALITY_NUMERIC) { throw new IllegalArgumentException("quality must be at least NUMERIC, but was " + requestedQuality); } final int currentQuality = getKeyguardStoredPasswordQuality(userHandle); final int passwordQuality = PasswordMetrics.computeForPassword(password.getCredential()).quality; final int newKeyguardQuality = computeKeyguardQuality(CREDENTIAL_TYPE_PASSWORD, requestedQuality, passwordQuality); setKeyguardStoredPasswordQuality(newKeyguardQuality, userHandle); try { getLockSettings().setLockCredential(password.getCredential(), password.getType(), savedCredential.getCredential(), requestedQuality, userHandle, allowUntrustedChange); } catch (RemoteException | RuntimeException e) { setKeyguardStoredPasswordQuality(currentQuality, userHandle); throw new RuntimeException("Unable to save lock password", e); } updateEncryptionPasswordIfNeeded(password.getCredential(), passwordQuality, userHandle); updatePasswordHistory(password, userHandle); onAfterChangingPassword(userHandle); return true; } /** * Compute keyguard credential quality to store in PASSWORD_TYPE_KEY by computing max between * them so that digit-only password is distinguished from PIN. * * TODO: remove this method and make CREDENTIAL_TYPE distinguish between PIN and password, so * that this quality is no longer needs to be persisted. */ private int computeKeyguardQuality( @CredentialType int credentialType, int requestedQuality, int passwordQuality) { return credentialType == CREDENTIAL_TYPE_PASSWORD ? Math.max(passwordQuality, requestedQuality) : passwordQuality; } /** * Update device encryption password if calling user is USER_SYSTEM and device supports * encryption. */ private void updateEncryptionPasswordIfNeeded(byte[] password, int quality, int userHandle) { private void updateEncryptionPasswordIfNeeded(LockscreenCredential credential, int userHandle) { // Update the device encryption password. if (userHandle == UserHandle.USER_SYSTEM && LockPatternUtils.isDeviceEncryptionEnabled()) { if (userHandle != UserHandle.USER_SYSTEM || !isDeviceEncryptionEnabled()) { return; } if (!shouldEncryptWithCredentials(true)) { clearEncryptionPassword(); } else { boolean numeric = quality == PASSWORD_QUALITY_NUMERIC; boolean numericComplex = quality == PASSWORD_QUALITY_NUMERIC_COMPLEX; int type = numeric || numericComplex ? StorageManager.CRYPT_TYPE_PIN : StorageManager.CRYPT_TYPE_PASSWORD; updateEncryptionPassword(type, password); updateEncryptionPassword(StorageManager.CRYPT_TYPE_DEFAULT, null); return; } if (credential.isNone()) { // Set the encryption password to default. setCredentialRequiredToDecrypt(false); } updateEncryptionPassword(credential.getStorageCryptType(), credential.getCredential()); } /** Loading @@ -973,7 +835,10 @@ public class LockPatternUtils { */ private void updatePasswordHistory(LockscreenCredential password, int userHandle) { if (password.isNone()) { Log.e(TAG, "checkPasswordHistory: empty password"); return; } if (password.isPattern()) { // Do not keep track of historical patterns return; } // Add the password to the password history. We assume all Loading Loading @@ -1065,7 +930,7 @@ public class LockPatternUtils { try { getLockSettings().setSeparateProfileChallengeEnabled(userHandle, enabled, managedUserPassword.getCredential()); onAfterChangingPassword(userHandle); reportEnabledTrustAgentsChanged(userHandle); } catch (RemoteException e) { Log.e(TAG, "Couldn't update work profile challenge enabled"); } Loading Loading @@ -1506,7 +1371,7 @@ public class LockPatternUtils { } } private void onAfterChangingPassword(int userHandle) { private void reportEnabledTrustAgentsChanged(int userHandle) { getTrustManager().reportEnabledTrustAgentsChanged(userHandle); } Loading Loading @@ -1674,48 +1539,34 @@ public class LockPatternUtils { * @param credential The new credential to be set * @param tokenHandle Handle of the escrow token * @param token Escrow token * @param userId The user who's lock credential to be changed * @param userHandle The user who's lock credential to be changed * @return {@code true} if the operation is successful. */ public boolean setLockCredentialWithToken(LockscreenCredential credential, long tokenHandle, byte[] token, int userId) { byte[] token, int userHandle) { if (!hasSecureLockScreen()) { throw new UnsupportedOperationException( "This operation requires the lock screen feature."); } credential.checkLength(); LockSettingsInternal localService = getLockSettingsInternal(); if (!credential.isNone()) { if (credential.size() < MIN_LOCK_PASSWORD_SIZE) { throw new IllegalArgumentException("password must not be null and at least " + "of length " + MIN_LOCK_PASSWORD_SIZE); } final int type = credential.getType(); final int quality = PasswordMetrics.computeForCredential(credential).quality; final int keyguardQuality = computeKeyguardQuality(type, quality, credential.getQuality()); if (!localService.setLockCredentialWithToken(credential.getCredential(), type, tokenHandle, token, keyguardQuality, userId)) { return false; } setKeyguardStoredPasswordQuality(quality, userId); updateEncryptionPasswordIfNeeded(credential.getCredential(), quality, userId); updatePasswordHistory(credential, userId); onAfterChangingPassword(userId); } else { if (!localService.setLockCredentialWithToken(null, CREDENTIAL_TYPE_NONE, tokenHandle, token, PASSWORD_QUALITY_UNSPECIFIED, userId)) { return false; } setKeyguardStoredPasswordQuality(PASSWORD_QUALITY_UNSPECIFIED, userId); final int currentQuality = getKeyguardStoredPasswordQuality(userHandle); setKeyguardStoredPasswordQuality(credential.getQuality(), userHandle); if (userId == UserHandle.USER_SYSTEM) { // Set the encryption password to default. updateEncryptionPassword(StorageManager.CRYPT_TYPE_DEFAULT, null); setCredentialRequiredToDecrypt(false); try { if (!localService.setLockCredentialWithToken(credential.getCredential(), credential.getType(), tokenHandle, token, credential.getType(), userHandle)) { setKeyguardStoredPasswordQuality(currentQuality, userHandle); return false; } } catch (RuntimeException e) { setKeyguardStoredPasswordQuality(currentQuality, userHandle); throw new RuntimeException("Unable to save lock credential", e); } onAfterChangingPassword(userId); onPostPasswordChanged(credential, userHandle); return true; } Loading
core/java/com/android/internal/widget/LockscreenCredential.java +45 −0 Original line number Diff line number Diff line Loading @@ -29,6 +29,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.os.Parcel; import android.os.Parcelable; import android.os.storage.StorageManager; import android.text.TextUtils; import com.android.internal.util.Preconditions; Loading Loading @@ -187,6 +188,25 @@ public class LockscreenCredential implements Parcelable, AutoCloseable { return mCredential; } /** * Returns the credential type recognized by {@link StorageManager}. Can be one of * {@link StorageManager#CRYPT_TYPE_DEFAULT}, {@link StorageManager#CRYPT_TYPE_PATTERN}, * {@link StorageManager#CRYPT_TYPE_PIN} or {@link StorageManager#CRYPT_TYPE_PASSWORD}. */ public int getStorageCryptType() { if (isNone()) { return StorageManager.CRYPT_TYPE_DEFAULT; } if (isPattern()) { return StorageManager.CRYPT_TYPE_PATTERN; } if (isPassword()) { return mQuality == PASSWORD_QUALITY_NUMERIC ? StorageManager.CRYPT_TYPE_PIN : StorageManager.CRYPT_TYPE_PASSWORD; } throw new IllegalStateException("Unhandled credential type"); } /** Returns whether this is an empty credential */ public boolean isNone() { ensureNotZeroized(); Loading Loading @@ -227,6 +247,31 @@ public class LockscreenCredential implements Parcelable, AutoCloseable { } } /** * Check if the credential meets minimal length requirement. * * @throws IllegalArgumentException if the credential is too short. */ public void checkLength() { if (isNone()) { return; } if (isPattern()) { if (size() < LockPatternUtils.MIN_LOCK_PATTERN_SIZE) { throw new IllegalArgumentException("pattern must not be null and at least " + LockPatternUtils.MIN_LOCK_PATTERN_SIZE + " dots long."); } return; } if (isPassword()) { if (size() < LockPatternUtils.MIN_LOCK_PASSWORD_SIZE) { throw new IllegalArgumentException("password must not be null and at least " + "of length " + LockPatternUtils.MIN_LOCK_PASSWORD_SIZE); } return; } } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeInt(mType); Loading
services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java +3 −3 Original line number Diff line number Diff line Loading @@ -513,7 +513,7 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { assertFalse(mService.havePattern(PRIMARY_USER_ID)); } public void testgetHashFactorPrimaryUser() throws RemoteException { public void testGetHashFactorPrimaryUser() throws RemoteException { final byte[] password = "password".getBytes(); mService.setLockCredential(password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null, PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID, false); Loading @@ -528,7 +528,7 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { assertArrayEquals(hashFactor, newHashFactor); } public void testgetHashFactorManagedProfileUnifiedChallenge() throws RemoteException { public void testGetHashFactorManagedProfileUnifiedChallenge() throws RemoteException { final byte[] pattern = "1236".getBytes(); mService.setLockCredential(pattern, LockPatternUtils.CREDENTIAL_TYPE_PATTERN, null, PASSWORD_QUALITY_SOMETHING, PRIMARY_USER_ID, false); Loading @@ -536,7 +536,7 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { assertNotNull(mService.getHashFactor(null, MANAGED_PROFILE_USER_ID)); } public void testgetHashFactorManagedProfileSeparateChallenge() throws RemoteException { public void testGetHashFactorManagedProfileSeparateChallenge() throws RemoteException { final byte[] primaryPassword = "primary".getBytes(); final byte[] profilePassword = "profile".getBytes(); mService.setLockCredential(primaryPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null, Loading