1 /* 2 * Copyright (C) 2007 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.internal.widget; 18 19 import android.Manifest; 20 import android.app.ActivityManager; 21 import android.app.ActivityManagerNative; 22 import android.app.admin.DevicePolicyManager; 23 import android.app.trust.TrustManager; 24 import android.bluetooth.BluetoothClass; 25 import android.content.ComponentName; 26 import android.content.ContentResolver; 27 import android.content.Context; 28 import android.content.pm.PackageManager; 29 import android.os.AsyncTask; 30 import android.os.IBinder; 31 import android.os.RemoteException; 32 import android.os.ServiceManager; 33 import android.os.SystemClock; 34 import android.os.SystemProperties; 35 import android.os.UserHandle; 36 import android.os.storage.IMountService; 37 import android.os.storage.StorageManager; 38 import android.provider.Settings; 39 import android.text.TextUtils; 40 import android.util.Log; 41 42 import com.google.android.collect.Lists; 43 44 import java.nio.charset.StandardCharsets; 45 import java.security.MessageDigest; 46 import java.security.NoSuchAlgorithmException; 47 import java.security.SecureRandom; 48 import java.util.ArrayList; 49 import java.util.Collection; 50 import java.util.List; 51 52 import libcore.util.HexEncoding; 53 54 /** 55 * Utilities for the lock pattern and its settings. 56 */ 57 public class LockPatternUtils { 58 59 private static final String TAG = "LockPatternUtils"; 60 private static final boolean DEBUG = false; 61 62 /** 63 * The number of incorrect attempts before which we fall back on an alternative 64 * method of verifying the user, and resetting their lock pattern. 65 */ 66 public static final int FAILED_ATTEMPTS_BEFORE_RESET = 20; 67 68 /** 69 * The interval of the countdown for showing progress of the lockout. 70 */ 71 public static final long FAILED_ATTEMPT_COUNTDOWN_INTERVAL_MS = 1000L; 72 73 74 /** 75 * This dictates when we start telling the user that continued failed attempts will wipe 76 * their device. 77 */ 78 public static final int FAILED_ATTEMPTS_BEFORE_WIPE_GRACE = 5; 79 80 /** 81 * The minimum number of dots in a valid pattern. 82 */ 83 public static final int MIN_LOCK_PATTERN_SIZE = 4; 84 85 /** 86 * The minimum size of a valid password. 87 */ 88 public static final int MIN_LOCK_PASSWORD_SIZE = 4; 89 90 /** 91 * The minimum number of dots the user must include in a wrong pattern 92 * attempt for it to be counted against the counts that affect 93 * {@link #FAILED_ATTEMPTS_BEFORE_TIMEOUT} and {@link #FAILED_ATTEMPTS_BEFORE_RESET} 94 */ 95 public static final int MIN_PATTERN_REGISTER_FAIL = MIN_LOCK_PATTERN_SIZE; 96 97 @Deprecated 98 public final static String LOCKOUT_PERMANENT_KEY = "lockscreen.lockedoutpermanently"; 99 public final static String LOCKOUT_ATTEMPT_DEADLINE = "lockscreen.lockoutattemptdeadline"; 100 public final static String LOCKOUT_ATTEMPT_TIMEOUT_MS = "lockscreen.lockoutattempttimeoutmss"; 101 public final static String PATTERN_EVER_CHOSEN_KEY = "lockscreen.patterneverchosen"; 102 public final static String PASSWORD_TYPE_KEY = "lockscreen.password_type"; 103 @Deprecated 104 public final static String PASSWORD_TYPE_ALTERNATE_KEY = "lockscreen.password_type_alternate"; 105 public final static String LOCK_PASSWORD_SALT_KEY = "lockscreen.password_salt"; 106 public final static String DISABLE_LOCKSCREEN_KEY = "lockscreen.disabled"; 107 public final static String LOCKSCREEN_OPTIONS = "lockscreen.options"; 108 @Deprecated 109 public final static String LOCKSCREEN_BIOMETRIC_WEAK_FALLBACK 110 = "lockscreen.biometric_weak_fallback"; 111 @Deprecated 112 public final static String BIOMETRIC_WEAK_EVER_CHOSEN_KEY 113 = "lockscreen.biometricweakeverchosen"; 114 public final static String LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS 115 = "lockscreen.power_button_instantly_locks"; 116 @Deprecated 117 public final static String LOCKSCREEN_WIDGETS_ENABLED = "lockscreen.widgets_enabled"; 118 119 public final static String PASSWORD_HISTORY_KEY = "lockscreen.passwordhistory"; 120 121 private static final String LOCK_SCREEN_OWNER_INFO = Settings.Secure.LOCK_SCREEN_OWNER_INFO; 122 private static final String LOCK_SCREEN_OWNER_INFO_ENABLED = 123 Settings.Secure.LOCK_SCREEN_OWNER_INFO_ENABLED; 124 125 private static final String ENABLED_TRUST_AGENTS = "lockscreen.enabledtrustagents"; 126 127 // Maximum allowed number of repeated or ordered characters in a sequence before we'll 128 // consider it a complex PIN/password. 129 public static final int MAX_ALLOWED_SEQUENCE = 3; 130 131 private final Context mContext; 132 private final ContentResolver mContentResolver; 133 private DevicePolicyManager mDevicePolicyManager; 134 private ILockSettings mLockSettingsService; 135 136 137 public static final class RequestThrottledException extends Exception { 138 private int mTimeoutMs; RequestThrottledException(int timeoutMs)139 public RequestThrottledException(int timeoutMs) { 140 mTimeoutMs = timeoutMs; 141 } 142 143 /** 144 * @return The amount of time in ms before another request may 145 * be executed 146 */ getTimeoutMs()147 public int getTimeoutMs() { 148 return mTimeoutMs; 149 } 150 151 } 152 getDevicePolicyManager()153 public DevicePolicyManager getDevicePolicyManager() { 154 if (mDevicePolicyManager == null) { 155 mDevicePolicyManager = 156 (DevicePolicyManager)mContext.getSystemService(Context.DEVICE_POLICY_SERVICE); 157 if (mDevicePolicyManager == null) { 158 Log.e(TAG, "Can't get DevicePolicyManagerService: is it running?", 159 new IllegalStateException("Stack trace:")); 160 } 161 } 162 return mDevicePolicyManager; 163 } 164 getTrustManager()165 private TrustManager getTrustManager() { 166 TrustManager trust = (TrustManager) mContext.getSystemService(Context.TRUST_SERVICE); 167 if (trust == null) { 168 Log.e(TAG, "Can't get TrustManagerService: is it running?", 169 new IllegalStateException("Stack trace:")); 170 } 171 return trust; 172 } 173 LockPatternUtils(Context context)174 public LockPatternUtils(Context context) { 175 mContext = context; 176 mContentResolver = context.getContentResolver(); 177 } 178 getLockSettings()179 private ILockSettings getLockSettings() { 180 if (mLockSettingsService == null) { 181 ILockSettings service = ILockSettings.Stub.asInterface( 182 ServiceManager.getService("lock_settings")); 183 mLockSettingsService = service; 184 } 185 return mLockSettingsService; 186 } 187 getRequestedMinimumPasswordLength(int userId)188 public int getRequestedMinimumPasswordLength(int userId) { 189 return getDevicePolicyManager().getPasswordMinimumLength(null, userId); 190 } 191 192 /** 193 * Gets the device policy password mode. If the mode is non-specific, returns 194 * MODE_PATTERN which allows the user to choose anything. 195 */ getRequestedPasswordQuality(int userId)196 public int getRequestedPasswordQuality(int userId) { 197 return getDevicePolicyManager().getPasswordQuality(null, userId); 198 } 199 getRequestedPasswordHistoryLength(int userId)200 private int getRequestedPasswordHistoryLength(int userId) { 201 return getDevicePolicyManager().getPasswordHistoryLength(null, userId); 202 } 203 getRequestedPasswordMinimumLetters(int userId)204 public int getRequestedPasswordMinimumLetters(int userId) { 205 return getDevicePolicyManager().getPasswordMinimumLetters(null, userId); 206 } 207 getRequestedPasswordMinimumUpperCase(int userId)208 public int getRequestedPasswordMinimumUpperCase(int userId) { 209 return getDevicePolicyManager().getPasswordMinimumUpperCase(null, userId); 210 } 211 getRequestedPasswordMinimumLowerCase(int userId)212 public int getRequestedPasswordMinimumLowerCase(int userId) { 213 return getDevicePolicyManager().getPasswordMinimumLowerCase(null, userId); 214 } 215 getRequestedPasswordMinimumNumeric(int userId)216 public int getRequestedPasswordMinimumNumeric(int userId) { 217 return getDevicePolicyManager().getPasswordMinimumNumeric(null, userId); 218 } 219 getRequestedPasswordMinimumSymbols(int userId)220 public int getRequestedPasswordMinimumSymbols(int userId) { 221 return getDevicePolicyManager().getPasswordMinimumSymbols(null, userId); 222 } 223 getRequestedPasswordMinimumNonLetter(int userId)224 public int getRequestedPasswordMinimumNonLetter(int userId) { 225 return getDevicePolicyManager().getPasswordMinimumNonLetter(null, userId); 226 } 227 reportFailedPasswordAttempt(int userId)228 public void reportFailedPasswordAttempt(int userId) { 229 getDevicePolicyManager().reportFailedPasswordAttempt(userId); 230 getTrustManager().reportUnlockAttempt(false /* authenticated */, userId); 231 getTrustManager().reportRequireCredentialEntry(userId); 232 } 233 reportSuccessfulPasswordAttempt(int userId)234 public void reportSuccessfulPasswordAttempt(int userId) { 235 getDevicePolicyManager().reportSuccessfulPasswordAttempt(userId); 236 getTrustManager().reportUnlockAttempt(true /* authenticated */, userId); 237 } 238 239 /** 240 * Check to see if a pattern matches the saved pattern. 241 * If pattern matches, return an opaque attestation that the challenge 242 * was verified. 243 * 244 * @param pattern The pattern to check. 245 * @param challenge The challenge to verify against the pattern 246 * @return the attestation that the challenge was verified, or null. 247 */ verifyPattern(List<LockPatternView.Cell> pattern, long challenge, int userId)248 public byte[] verifyPattern(List<LockPatternView.Cell> pattern, long challenge, int userId) 249 throws RequestThrottledException { 250 try { 251 VerifyCredentialResponse response = 252 getLockSettings().verifyPattern(patternToString(pattern), challenge, userId); 253 if (response == null) { 254 // Shouldn't happen 255 return null; 256 } 257 258 if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) { 259 return response.getPayload(); 260 } else if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_RETRY) { 261 throw new RequestThrottledException(response.getTimeout()); 262 } else { 263 return null; 264 } 265 } catch (RemoteException re) { 266 return null; 267 } 268 } 269 270 /** 271 * Check to see if a pattern matches the saved pattern. If no pattern exists, 272 * always returns true. 273 * @param pattern The pattern to check. 274 * @return Whether the pattern matches the stored one. 275 */ checkPattern(List<LockPatternView.Cell> pattern, int userId)276 public boolean checkPattern(List<LockPatternView.Cell> pattern, int userId) 277 throws RequestThrottledException { 278 try { 279 VerifyCredentialResponse response = 280 getLockSettings().checkPattern(patternToString(pattern), userId); 281 282 if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) { 283 return true; 284 } else if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_RETRY) { 285 throw new RequestThrottledException(response.getTimeout()); 286 } else { 287 return false; 288 } 289 } catch (RemoteException re) { 290 return true; 291 } 292 } 293 294 /** 295 * Check to see if a password matches the saved password. 296 * If password matches, return an opaque attestation that the challenge 297 * was verified. 298 * 299 * @param password The password to check. 300 * @param challenge The challenge to verify against the password 301 * @return the attestation that the challenge was verified, or null. 302 */ verifyPassword(String password, long challenge, int userId)303 public byte[] verifyPassword(String password, long challenge, int userId) 304 throws RequestThrottledException { 305 try { 306 VerifyCredentialResponse response = 307 getLockSettings().verifyPassword(password, challenge, userId); 308 309 if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) { 310 return response.getPayload(); 311 } else if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_RETRY) { 312 throw new RequestThrottledException(response.getTimeout()); 313 } else { 314 return null; 315 } 316 } catch (RemoteException re) { 317 return null; 318 } 319 } 320 321 /** 322 * Check to see if a password matches the saved password. If no password exists, 323 * always returns true. 324 * @param password The password to check. 325 * @return Whether the password matches the stored one. 326 */ checkPassword(String password, int userId)327 public boolean checkPassword(String password, int userId) throws RequestThrottledException { 328 try { 329 VerifyCredentialResponse response = 330 getLockSettings().checkPassword(password, userId); 331 if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) { 332 return true; 333 } else if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_RETRY) { 334 throw new RequestThrottledException(response.getTimeout()); 335 } else { 336 return false; 337 } 338 } catch (RemoteException re) { 339 return true; 340 } 341 } 342 343 /** 344 * Check to see if vold already has the password. 345 * Note that this also clears vold's copy of the password. 346 * @return Whether the vold password matches or not. 347 */ checkVoldPassword(int userId)348 public boolean checkVoldPassword(int userId) { 349 try { 350 return getLockSettings().checkVoldPassword(userId); 351 } catch (RemoteException re) { 352 return false; 353 } 354 } 355 356 /** 357 * Check to see if a password matches any of the passwords stored in the 358 * password history. 359 * 360 * @param password The password to check. 361 * @return Whether the password matches any in the history. 362 */ checkPasswordHistory(String password, int userId)363 public boolean checkPasswordHistory(String password, int userId) { 364 String passwordHashString = new String( 365 passwordToHash(password, userId), StandardCharsets.UTF_8); 366 String passwordHistory = getString(PASSWORD_HISTORY_KEY, userId); 367 if (passwordHistory == null) { 368 return false; 369 } 370 // Password History may be too long... 371 int passwordHashLength = passwordHashString.length(); 372 int passwordHistoryLength = getRequestedPasswordHistoryLength(userId); 373 if(passwordHistoryLength == 0) { 374 return false; 375 } 376 int neededPasswordHistoryLength = passwordHashLength * passwordHistoryLength 377 + passwordHistoryLength - 1; 378 if (passwordHistory.length() > neededPasswordHistoryLength) { 379 passwordHistory = passwordHistory.substring(0, neededPasswordHistoryLength); 380 } 381 return passwordHistory.contains(passwordHashString); 382 } 383 384 /** 385 * Check to see if the user has stored a lock pattern. 386 * @return Whether a saved pattern exists. 387 */ savedPatternExists(int userId)388 private boolean savedPatternExists(int userId) { 389 try { 390 return getLockSettings().havePattern(userId); 391 } catch (RemoteException re) { 392 return false; 393 } 394 } 395 396 /** 397 * Check to see if the user has stored a lock pattern. 398 * @return Whether a saved pattern exists. 399 */ savedPasswordExists(int userId)400 private boolean savedPasswordExists(int userId) { 401 try { 402 return getLockSettings().havePassword(userId); 403 } catch (RemoteException re) { 404 return false; 405 } 406 } 407 408 /** 409 * Return true if the user has ever chosen a pattern. This is true even if the pattern is 410 * currently cleared. 411 * 412 * @return True if the user has ever chosen a pattern. 413 */ isPatternEverChosen(int userId)414 public boolean isPatternEverChosen(int userId) { 415 return getBoolean(PATTERN_EVER_CHOSEN_KEY, false, userId); 416 } 417 418 /** 419 * Used by device policy manager to validate the current password 420 * information it has. 421 */ getActivePasswordQuality(int userId)422 public int getActivePasswordQuality(int userId) { 423 int quality = getKeyguardStoredPasswordQuality(userId); 424 425 if (isLockPasswordEnabled(quality, userId)) { 426 // Quality is a password and a password exists. Return the quality. 427 return quality; 428 } 429 430 if (isLockPatternEnabled(quality, userId)) { 431 // Quality is a pattern and a pattern exists. Return the quality. 432 return quality; 433 } 434 435 return DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED; 436 } 437 438 /** 439 * Clear any lock pattern or password. 440 */ clearLock(int userHandle)441 public void clearLock(int userHandle) { 442 setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, userHandle); 443 444 try { 445 getLockSettings().setLockPassword(null, null, userHandle); 446 getLockSettings().setLockPattern(null, null, userHandle); 447 } catch (RemoteException e) { 448 // well, we tried... 449 } 450 451 if (userHandle == UserHandle.USER_OWNER) { 452 // Set the encryption password to default. 453 updateEncryptionPassword(StorageManager.CRYPT_TYPE_DEFAULT, null); 454 } 455 456 setCredentialRequiredToDecrypt(false); 457 458 getDevicePolicyManager().setActivePasswordState( 459 DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, 0, 0, 0, 0, 0, 0, 0, userHandle); 460 461 onAfterChangingPassword(userHandle); 462 } 463 464 /** 465 * Disable showing lock screen at all for a given user. 466 * This is only meaningful if pattern, pin or password are not set. 467 * 468 * @param disable Disables lock screen when true 469 * @param userId User ID of the user this has effect on 470 */ setLockScreenDisabled(boolean disable, int userId)471 public void setLockScreenDisabled(boolean disable, int userId) { 472 setBoolean(DISABLE_LOCKSCREEN_KEY, disable, userId); 473 } 474 475 /** 476 * Determine if LockScreen is disabled for the current user. This is used to decide whether 477 * LockScreen is shown after reboot or after screen timeout / short press on power. 478 * 479 * @return true if lock screen is disabled 480 */ isLockScreenDisabled(int userId)481 public boolean isLockScreenDisabled(int userId) { 482 return !isSecure(userId) && 483 getBoolean(DISABLE_LOCKSCREEN_KEY, false, userId); 484 } 485 486 /** 487 * Save a lock pattern. 488 * @param pattern The new pattern to save. 489 * @param userId the user whose pattern is to be saved. 490 */ saveLockPattern(List<LockPatternView.Cell> pattern, int userId)491 public void saveLockPattern(List<LockPatternView.Cell> pattern, int userId) { 492 this.saveLockPattern(pattern, null, userId); 493 } 494 /** 495 * Save a lock pattern. 496 * @param pattern The new pattern to save. 497 * @param savedPattern The previously saved pattern, converted to String format 498 * @param userId the user whose pattern is to be saved. 499 */ saveLockPattern(List<LockPatternView.Cell> pattern, String savedPattern, int userId)500 public void saveLockPattern(List<LockPatternView.Cell> pattern, String savedPattern, int userId) { 501 try { 502 if (pattern == null || pattern.size() < MIN_LOCK_PATTERN_SIZE) { 503 throw new IllegalArgumentException("pattern must not be null and at least " 504 + MIN_LOCK_PATTERN_SIZE + " dots long."); 505 } 506 507 getLockSettings().setLockPattern(patternToString(pattern), savedPattern, userId); 508 DevicePolicyManager dpm = getDevicePolicyManager(); 509 510 // Update the device encryption password. 511 if (userId == UserHandle.USER_OWNER 512 && LockPatternUtils.isDeviceEncryptionEnabled()) { 513 if (!shouldEncryptWithCredentials(true)) { 514 clearEncryptionPassword(); 515 } else { 516 String stringPattern = patternToString(pattern); 517 updateEncryptionPassword(StorageManager.CRYPT_TYPE_PATTERN, stringPattern); 518 } 519 } 520 521 setBoolean(PATTERN_EVER_CHOSEN_KEY, true, userId); 522 523 setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING, userId); 524 dpm.setActivePasswordState(DevicePolicyManager.PASSWORD_QUALITY_SOMETHING, 525 pattern.size(), 0, 0, 0, 0, 0, 0, userId); 526 onAfterChangingPassword(userId); 527 } catch (RemoteException re) { 528 Log.e(TAG, "Couldn't save lock pattern " + re); 529 } 530 } 531 updateCryptoUserInfo(int userId)532 private void updateCryptoUserInfo(int userId) { 533 if (userId != UserHandle.USER_OWNER) { 534 return; 535 } 536 537 final String ownerInfo = isOwnerInfoEnabled(userId) ? getOwnerInfo(userId) : ""; 538 539 IBinder service = ServiceManager.getService("mount"); 540 if (service == null) { 541 Log.e(TAG, "Could not find the mount service to update the user info"); 542 return; 543 } 544 545 IMountService mountService = IMountService.Stub.asInterface(service); 546 try { 547 Log.d(TAG, "Setting owner info"); 548 mountService.setField(StorageManager.OWNER_INFO_KEY, ownerInfo); 549 } catch (RemoteException e) { 550 Log.e(TAG, "Error changing user info", e); 551 } 552 } 553 setOwnerInfo(String info, int userId)554 public void setOwnerInfo(String info, int userId) { 555 setString(LOCK_SCREEN_OWNER_INFO, info, userId); 556 updateCryptoUserInfo(userId); 557 } 558 setOwnerInfoEnabled(boolean enabled, int userId)559 public void setOwnerInfoEnabled(boolean enabled, int userId) { 560 setBoolean(LOCK_SCREEN_OWNER_INFO_ENABLED, enabled, userId); 561 updateCryptoUserInfo(userId); 562 } 563 getOwnerInfo(int userId)564 public String getOwnerInfo(int userId) { 565 return getString(LOCK_SCREEN_OWNER_INFO, userId); 566 } 567 isOwnerInfoEnabled(int userId)568 public boolean isOwnerInfoEnabled(int userId) { 569 return getBoolean(LOCK_SCREEN_OWNER_INFO_ENABLED, false, userId); 570 } 571 572 /** 573 * Compute the password quality from the given password string. 574 */ computePasswordQuality(String password)575 static public int computePasswordQuality(String password) { 576 boolean hasDigit = false; 577 boolean hasNonDigit = false; 578 final int len = password.length(); 579 for (int i = 0; i < len; i++) { 580 if (Character.isDigit(password.charAt(i))) { 581 hasDigit = true; 582 } else { 583 hasNonDigit = true; 584 } 585 } 586 587 if (hasNonDigit && hasDigit) { 588 return DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC; 589 } 590 if (hasNonDigit) { 591 return DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC; 592 } 593 if (hasDigit) { 594 return maxLengthSequence(password) > MAX_ALLOWED_SEQUENCE 595 ? DevicePolicyManager.PASSWORD_QUALITY_NUMERIC 596 : DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX; 597 } 598 return DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED; 599 } 600 categoryChar(char c)601 private static int categoryChar(char c) { 602 if ('a' <= c && c <= 'z') return 0; 603 if ('A' <= c && c <= 'Z') return 1; 604 if ('0' <= c && c <= '9') return 2; 605 return 3; 606 } 607 maxDiffCategory(int category)608 private static int maxDiffCategory(int category) { 609 if (category == 0 || category == 1) return 1; 610 else if (category == 2) return 10; 611 return 0; 612 } 613 614 /* 615 * Returns the maximum length of a sequential characters. A sequence is defined as 616 * monotonically increasing characters with a constant interval or the same character repeated. 617 * 618 * For example: 619 * maxLengthSequence("1234") == 4 620 * maxLengthSequence("1234abc") == 4 621 * maxLengthSequence("aabc") == 3 622 * maxLengthSequence("qwertyuio") == 1 623 * maxLengthSequence("@ABC") == 3 624 * maxLengthSequence(";;;;") == 4 (anything that repeats) 625 * maxLengthSequence(":;<=>") == 1 (ordered, but not composed of alphas or digits) 626 * 627 * @param string the pass 628 * @return the number of sequential letters or digits 629 */ maxLengthSequence(String string)630 public static int maxLengthSequence(String string) { 631 if (string.length() == 0) return 0; 632 char previousChar = string.charAt(0); 633 int category = categoryChar(previousChar); //current category of the sequence 634 int diff = 0; //difference between two consecutive characters 635 boolean hasDiff = false; //if we are currently targeting a sequence 636 int maxLength = 0; //maximum length of a sequence already found 637 int startSequence = 0; //where the current sequence started 638 for (int current = 1; current < string.length(); current++) { 639 char currentChar = string.charAt(current); 640 int categoryCurrent = categoryChar(currentChar); 641 int currentDiff = (int) currentChar - (int) previousChar; 642 if (categoryCurrent != category || Math.abs(currentDiff) > maxDiffCategory(category)) { 643 maxLength = Math.max(maxLength, current - startSequence); 644 startSequence = current; 645 hasDiff = false; 646 category = categoryCurrent; 647 } 648 else { 649 if(hasDiff && currentDiff != diff) { 650 maxLength = Math.max(maxLength, current - startSequence); 651 startSequence = current - 1; 652 } 653 diff = currentDiff; 654 hasDiff = true; 655 } 656 previousChar = currentChar; 657 } 658 maxLength = Math.max(maxLength, string.length() - startSequence); 659 return maxLength; 660 } 661 662 /** Update the encryption password if it is enabled **/ updateEncryptionPassword(final int type, final String password)663 private void updateEncryptionPassword(final int type, final String password) { 664 if (!isDeviceEncryptionEnabled()) { 665 return; 666 } 667 final IBinder service = ServiceManager.getService("mount"); 668 if (service == null) { 669 Log.e(TAG, "Could not find the mount service to update the encryption password"); 670 return; 671 } 672 673 new AsyncTask<Void, Void, Void>() { 674 @Override 675 protected Void doInBackground(Void... dummy) { 676 IMountService mountService = IMountService.Stub.asInterface(service); 677 try { 678 mountService.changeEncryptionPassword(type, password); 679 } catch (RemoteException e) { 680 Log.e(TAG, "Error changing encryption password", e); 681 } 682 return null; 683 } 684 }.execute(); 685 } 686 687 /** 688 * Save a lock password. Does not ensure that the password is as good 689 * as the requested mode, but will adjust the mode to be as good as the 690 * password. 691 * @param password The password to save 692 * @param savedPassword The previously saved lock password, or null if none 693 * @param quality {@see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)} 694 * @param userHandle The userId of the user to change the password for 695 */ saveLockPassword(String password, String savedPassword, int quality, int userHandle)696 public void saveLockPassword(String password, String savedPassword, int quality, 697 int userHandle) { 698 try { 699 DevicePolicyManager dpm = getDevicePolicyManager(); 700 if (password == null || password.length() < MIN_LOCK_PASSWORD_SIZE) { 701 throw new IllegalArgumentException("password must not be null and at least " 702 + "of length " + MIN_LOCK_PASSWORD_SIZE); 703 } 704 705 getLockSettings().setLockPassword(password, savedPassword, userHandle); 706 int computedQuality = computePasswordQuality(password); 707 708 // Update the device encryption password. 709 if (userHandle == UserHandle.USER_OWNER 710 && LockPatternUtils.isDeviceEncryptionEnabled()) { 711 if (!shouldEncryptWithCredentials(true)) { 712 clearEncryptionPassword(); 713 } else { 714 boolean numeric = computedQuality 715 == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC; 716 boolean numericComplex = computedQuality 717 == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX; 718 int type = numeric || numericComplex ? StorageManager.CRYPT_TYPE_PIN 719 : StorageManager.CRYPT_TYPE_PASSWORD; 720 updateEncryptionPassword(type, password); 721 } 722 } 723 724 setLong(PASSWORD_TYPE_KEY, Math.max(quality, computedQuality), userHandle); 725 if (computedQuality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) { 726 int letters = 0; 727 int uppercase = 0; 728 int lowercase = 0; 729 int numbers = 0; 730 int symbols = 0; 731 int nonletter = 0; 732 for (int i = 0; i < password.length(); i++) { 733 char c = password.charAt(i); 734 if (c >= 'A' && c <= 'Z') { 735 letters++; 736 uppercase++; 737 } else if (c >= 'a' && c <= 'z') { 738 letters++; 739 lowercase++; 740 } else if (c >= '0' && c <= '9') { 741 numbers++; 742 nonletter++; 743 } else { 744 symbols++; 745 nonletter++; 746 } 747 } 748 dpm.setActivePasswordState(Math.max(quality, computedQuality), 749 password.length(), letters, uppercase, lowercase, 750 numbers, symbols, nonletter, userHandle); 751 } else { 752 // The password is not anything. 753 dpm.setActivePasswordState( 754 DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, 755 0, 0, 0, 0, 0, 0, 0, userHandle); 756 } 757 758 // Add the password to the password history. We assume all 759 // password hashes have the same length for simplicity of implementation. 760 String passwordHistory = getString(PASSWORD_HISTORY_KEY, userHandle); 761 if (passwordHistory == null) { 762 passwordHistory = ""; 763 } 764 int passwordHistoryLength = getRequestedPasswordHistoryLength(userHandle); 765 if (passwordHistoryLength == 0) { 766 passwordHistory = ""; 767 } else { 768 byte[] hash = passwordToHash(password, userHandle); 769 passwordHistory = new String(hash, StandardCharsets.UTF_8) + "," + passwordHistory; 770 // Cut it to contain passwordHistoryLength hashes 771 // and passwordHistoryLength -1 commas. 772 passwordHistory = passwordHistory.substring(0, Math.min(hash.length 773 * passwordHistoryLength + passwordHistoryLength - 1, passwordHistory 774 .length())); 775 } 776 setString(PASSWORD_HISTORY_KEY, passwordHistory, userHandle); 777 onAfterChangingPassword(userHandle); 778 } catch (RemoteException re) { 779 // Cant do much 780 Log.e(TAG, "Unable to save lock password " + re); 781 } 782 } 783 784 /** 785 * Gets whether the device is encrypted. 786 * 787 * @return Whether the device is encrypted. 788 */ isDeviceEncrypted()789 public static boolean isDeviceEncrypted() { 790 IMountService mountService = IMountService.Stub.asInterface( 791 ServiceManager.getService("mount")); 792 try { 793 return mountService.getEncryptionState() != IMountService.ENCRYPTION_STATE_NONE 794 && mountService.getPasswordType() != StorageManager.CRYPT_TYPE_DEFAULT; 795 } catch (RemoteException re) { 796 Log.e(TAG, "Error getting encryption state", re); 797 } 798 return true; 799 } 800 801 /** 802 * Determine if the device supports encryption, even if it's set to default. This 803 * differs from isDeviceEncrypted() in that it returns true even if the device is 804 * encrypted with the default password. 805 * @return true if device encryption is enabled 806 */ isDeviceEncryptionEnabled()807 public static boolean isDeviceEncryptionEnabled() { 808 final String status = SystemProperties.get("ro.crypto.state", "unsupported"); 809 return "encrypted".equalsIgnoreCase(status); 810 } 811 812 /** 813 * Clears the encryption password. 814 */ clearEncryptionPassword()815 public void clearEncryptionPassword() { 816 updateEncryptionPassword(StorageManager.CRYPT_TYPE_DEFAULT, null); 817 } 818 819 /** 820 * Retrieves the quality mode for {@param userHandle}. 821 * {@see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)} 822 * 823 * @return stored password quality 824 */ getKeyguardStoredPasswordQuality(int userHandle)825 public int getKeyguardStoredPasswordQuality(int userHandle) { 826 return (int) getLong(PASSWORD_TYPE_KEY, 827 DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, userHandle); 828 } 829 830 /** 831 * Deserialize a pattern. 832 * @param string The pattern serialized with {@link #patternToString} 833 * @return The pattern. 834 */ stringToPattern(String string)835 public static List<LockPatternView.Cell> stringToPattern(String string) { 836 if (string == null) { 837 return null; 838 } 839 840 List<LockPatternView.Cell> result = Lists.newArrayList(); 841 842 final byte[] bytes = string.getBytes(); 843 for (int i = 0; i < bytes.length; i++) { 844 byte b = (byte) (bytes[i] - '1'); 845 result.add(LockPatternView.Cell.of(b / 3, b % 3)); 846 } 847 return result; 848 } 849 850 /** 851 * Serialize a pattern. 852 * @param pattern The pattern. 853 * @return The pattern in string form. 854 */ patternToString(List<LockPatternView.Cell> pattern)855 public static String patternToString(List<LockPatternView.Cell> pattern) { 856 if (pattern == null) { 857 return ""; 858 } 859 final int patternSize = pattern.size(); 860 861 byte[] res = new byte[patternSize]; 862 for (int i = 0; i < patternSize; i++) { 863 LockPatternView.Cell cell = pattern.get(i); 864 res[i] = (byte) (cell.getRow() * 3 + cell.getColumn() + '1'); 865 } 866 return new String(res); 867 } 868 patternStringToBaseZero(String pattern)869 public static String patternStringToBaseZero(String pattern) { 870 if (pattern == null) { 871 return ""; 872 } 873 final int patternSize = pattern.length(); 874 875 byte[] res = new byte[patternSize]; 876 final byte[] bytes = pattern.getBytes(); 877 for (int i = 0; i < patternSize; i++) { 878 res[i] = (byte) (bytes[i] - '1'); 879 } 880 return new String(res); 881 } 882 883 /* 884 * Generate an SHA-1 hash for the pattern. Not the most secure, but it is 885 * at least a second level of protection. First level is that the file 886 * is in a location only readable by the system process. 887 * @param pattern the gesture pattern. 888 * @return the hash of the pattern in a byte array. 889 */ patternToHash(List<LockPatternView.Cell> pattern)890 public static byte[] patternToHash(List<LockPatternView.Cell> pattern) { 891 if (pattern == null) { 892 return null; 893 } 894 895 final int patternSize = pattern.size(); 896 byte[] res = new byte[patternSize]; 897 for (int i = 0; i < patternSize; i++) { 898 LockPatternView.Cell cell = pattern.get(i); 899 res[i] = (byte) (cell.getRow() * 3 + cell.getColumn()); 900 } 901 try { 902 MessageDigest md = MessageDigest.getInstance("SHA-1"); 903 byte[] hash = md.digest(res); 904 return hash; 905 } catch (NoSuchAlgorithmException nsa) { 906 return res; 907 } 908 } 909 getSalt(int userId)910 private String getSalt(int userId) { 911 long salt = getLong(LOCK_PASSWORD_SALT_KEY, 0, userId); 912 if (salt == 0) { 913 try { 914 salt = SecureRandom.getInstance("SHA1PRNG").nextLong(); 915 setLong(LOCK_PASSWORD_SALT_KEY, salt, userId); 916 Log.v(TAG, "Initialized lock password salt for user: " + userId); 917 } catch (NoSuchAlgorithmException e) { 918 // Throw an exception rather than storing a password we'll never be able to recover 919 throw new IllegalStateException("Couldn't get SecureRandom number", e); 920 } 921 } 922 return Long.toHexString(salt); 923 } 924 925 /* 926 * Generate a hash for the given password. To avoid brute force attacks, we use a salted hash. 927 * Not the most secure, but it is at least a second level of protection. First level is that 928 * the file is in a location only readable by the system process. 929 * 930 * @param password the gesture pattern. 931 * 932 * @return the hash of the pattern in a byte array. 933 */ passwordToHash(String password, int userId)934 public byte[] passwordToHash(String password, int userId) { 935 if (password == null) { 936 return null; 937 } 938 939 try { 940 byte[] saltedPassword = (password + getSalt(userId)).getBytes(); 941 byte[] sha1 = MessageDigest.getInstance("SHA-1").digest(saltedPassword); 942 byte[] md5 = MessageDigest.getInstance("MD5").digest(saltedPassword); 943 944 byte[] combined = new byte[sha1.length + md5.length]; 945 System.arraycopy(sha1, 0, combined, 0, sha1.length); 946 System.arraycopy(md5, 0, combined, sha1.length, md5.length); 947 948 final char[] hexEncoded = HexEncoding.encode(combined); 949 return new String(hexEncoded).getBytes(StandardCharsets.UTF_8); 950 } catch (NoSuchAlgorithmException e) { 951 throw new AssertionError("Missing digest algorithm: ", e); 952 } 953 } 954 955 /** 956 * @param userId the user for which to report the value 957 * @return Whether the lock screen is secured. 958 */ isSecure(int userId)959 public boolean isSecure(int userId) { 960 int mode = getKeyguardStoredPasswordQuality(userId); 961 return isLockPatternEnabled(mode, userId) || isLockPasswordEnabled(mode, userId); 962 } 963 isLockPasswordEnabled(int userId)964 public boolean isLockPasswordEnabled(int userId) { 965 return isLockPasswordEnabled(getKeyguardStoredPasswordQuality(userId), userId); 966 } 967 isLockPasswordEnabled(int mode, int userId)968 private boolean isLockPasswordEnabled(int mode, int userId) { 969 final boolean passwordEnabled = mode == DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC 970 || mode == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC 971 || mode == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX 972 || mode == DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC 973 || mode == DevicePolicyManager.PASSWORD_QUALITY_COMPLEX; 974 return passwordEnabled && savedPasswordExists(userId); 975 } 976 977 /** 978 * @return Whether the lock pattern is enabled 979 */ isLockPatternEnabled(int userId)980 public boolean isLockPatternEnabled(int userId) { 981 return isLockPatternEnabled(getKeyguardStoredPasswordQuality(userId), userId); 982 } 983 isLockPatternEnabled(int mode, int userId)984 private boolean isLockPatternEnabled(int mode, int userId) { 985 return mode == DevicePolicyManager.PASSWORD_QUALITY_SOMETHING 986 && savedPatternExists(userId); 987 } 988 989 /** 990 * @return Whether the visible pattern is enabled. 991 */ isVisiblePatternEnabled(int userId)992 public boolean isVisiblePatternEnabled(int userId) { 993 return getBoolean(Settings.Secure.LOCK_PATTERN_VISIBLE, false, userId); 994 } 995 996 /** 997 * Set whether the visible pattern is enabled. 998 */ setVisiblePatternEnabled(boolean enabled, int userId)999 public void setVisiblePatternEnabled(boolean enabled, int userId) { 1000 setBoolean(Settings.Secure.LOCK_PATTERN_VISIBLE, enabled, userId); 1001 1002 // Update for crypto if owner 1003 if (userId != UserHandle.USER_OWNER) { 1004 return; 1005 } 1006 1007 IBinder service = ServiceManager.getService("mount"); 1008 if (service == null) { 1009 Log.e(TAG, "Could not find the mount service to update the user info"); 1010 return; 1011 } 1012 1013 IMountService mountService = IMountService.Stub.asInterface(service); 1014 try { 1015 mountService.setField(StorageManager.PATTERN_VISIBLE_KEY, enabled ? "1" : "0"); 1016 } catch (RemoteException e) { 1017 Log.e(TAG, "Error changing pattern visible state", e); 1018 } 1019 } 1020 1021 /** 1022 * Set whether the visible password is enabled for cryptkeeper screen. 1023 */ setVisiblePasswordEnabled(boolean enabled, int userId)1024 public void setVisiblePasswordEnabled(boolean enabled, int userId) { 1025 // Update for crypto if owner 1026 if (userId != UserHandle.USER_OWNER) { 1027 return; 1028 } 1029 1030 IBinder service = ServiceManager.getService("mount"); 1031 if (service == null) { 1032 Log.e(TAG, "Could not find the mount service to update the user info"); 1033 return; 1034 } 1035 1036 IMountService mountService = IMountService.Stub.asInterface(service); 1037 try { 1038 mountService.setField(StorageManager.PASSWORD_VISIBLE_KEY, enabled ? "1" : "0"); 1039 } catch (RemoteException e) { 1040 Log.e(TAG, "Error changing password visible state", e); 1041 } 1042 } 1043 1044 /** 1045 * @return Whether tactile feedback for the pattern is enabled. 1046 */ isTactileFeedbackEnabled()1047 public boolean isTactileFeedbackEnabled() { 1048 return Settings.System.getIntForUser(mContentResolver, 1049 Settings.System.HAPTIC_FEEDBACK_ENABLED, 1, UserHandle.USER_CURRENT) != 0; 1050 } 1051 1052 /** 1053 * Set and store the lockout deadline, meaning the user can't attempt his/her unlock 1054 * pattern until the deadline has passed. 1055 * @return the chosen deadline. 1056 */ setLockoutAttemptDeadline(int userId, int timeoutMs)1057 public long setLockoutAttemptDeadline(int userId, int timeoutMs) { 1058 final long deadline = SystemClock.elapsedRealtime() + timeoutMs; 1059 setLong(LOCKOUT_ATTEMPT_DEADLINE, deadline, userId); 1060 setLong(LOCKOUT_ATTEMPT_TIMEOUT_MS, timeoutMs, userId); 1061 return deadline; 1062 } 1063 1064 /** 1065 * @return The elapsed time in millis in the future when the user is allowed to 1066 * attempt to enter his/her lock pattern, or 0 if the user is welcome to 1067 * enter a pattern. 1068 */ getLockoutAttemptDeadline(int userId)1069 public long getLockoutAttemptDeadline(int userId) { 1070 final long deadline = getLong(LOCKOUT_ATTEMPT_DEADLINE, 0L, userId); 1071 final long timeoutMs = getLong(LOCKOUT_ATTEMPT_TIMEOUT_MS, 0L, userId); 1072 final long now = SystemClock.elapsedRealtime(); 1073 if (deadline < now || deadline > (now + timeoutMs)) { 1074 return 0L; 1075 } 1076 return deadline; 1077 } 1078 getBoolean(String secureSettingKey, boolean defaultValue, int userId)1079 private boolean getBoolean(String secureSettingKey, boolean defaultValue, int userId) { 1080 try { 1081 return getLockSettings().getBoolean(secureSettingKey, defaultValue, userId); 1082 } catch (RemoteException re) { 1083 return defaultValue; 1084 } 1085 } 1086 setBoolean(String secureSettingKey, boolean enabled, int userId)1087 private void setBoolean(String secureSettingKey, boolean enabled, int userId) { 1088 try { 1089 getLockSettings().setBoolean(secureSettingKey, enabled, userId); 1090 } catch (RemoteException re) { 1091 // What can we do? 1092 Log.e(TAG, "Couldn't write boolean " + secureSettingKey + re); 1093 } 1094 } 1095 getLong(String secureSettingKey, long defaultValue, int userHandle)1096 private long getLong(String secureSettingKey, long defaultValue, int userHandle) { 1097 try { 1098 return getLockSettings().getLong(secureSettingKey, defaultValue, userHandle); 1099 } catch (RemoteException re) { 1100 return defaultValue; 1101 } 1102 } 1103 setLong(String secureSettingKey, long value, int userHandle)1104 private void setLong(String secureSettingKey, long value, int userHandle) { 1105 try { 1106 getLockSettings().setLong(secureSettingKey, value, userHandle); 1107 } catch (RemoteException re) { 1108 // What can we do? 1109 Log.e(TAG, "Couldn't write long " + secureSettingKey + re); 1110 } 1111 } 1112 getString(String secureSettingKey, int userHandle)1113 private String getString(String secureSettingKey, int userHandle) { 1114 try { 1115 return getLockSettings().getString(secureSettingKey, null, userHandle); 1116 } catch (RemoteException re) { 1117 return null; 1118 } 1119 } 1120 setString(String secureSettingKey, String value, int userHandle)1121 private void setString(String secureSettingKey, String value, int userHandle) { 1122 try { 1123 getLockSettings().setString(secureSettingKey, value, userHandle); 1124 } catch (RemoteException re) { 1125 // What can we do? 1126 Log.e(TAG, "Couldn't write string " + secureSettingKey + re); 1127 } 1128 } 1129 setPowerButtonInstantlyLocks(boolean enabled, int userId)1130 public void setPowerButtonInstantlyLocks(boolean enabled, int userId) { 1131 setBoolean(LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS, enabled, userId); 1132 } 1133 getPowerButtonInstantlyLocks(int userId)1134 public boolean getPowerButtonInstantlyLocks(int userId) { 1135 return getBoolean(LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS, true, userId); 1136 } 1137 setEnabledTrustAgents(Collection<ComponentName> activeTrustAgents, int userId)1138 public void setEnabledTrustAgents(Collection<ComponentName> activeTrustAgents, int userId) { 1139 StringBuilder sb = new StringBuilder(); 1140 for (ComponentName cn : activeTrustAgents) { 1141 if (sb.length() > 0) { 1142 sb.append(','); 1143 } 1144 sb.append(cn.flattenToShortString()); 1145 } 1146 setString(ENABLED_TRUST_AGENTS, sb.toString(), userId); 1147 getTrustManager().reportEnabledTrustAgentsChanged(userId); 1148 } 1149 getEnabledTrustAgents(int userId)1150 public List<ComponentName> getEnabledTrustAgents(int userId) { 1151 String serialized = getString(ENABLED_TRUST_AGENTS, userId); 1152 if (TextUtils.isEmpty(serialized)) { 1153 return null; 1154 } 1155 String[] split = serialized.split(","); 1156 ArrayList<ComponentName> activeTrustAgents = new ArrayList<ComponentName>(split.length); 1157 for (String s : split) { 1158 if (!TextUtils.isEmpty(s)) { 1159 activeTrustAgents.add(ComponentName.unflattenFromString(s)); 1160 } 1161 } 1162 return activeTrustAgents; 1163 } 1164 1165 /** 1166 * @see android.app.trust.TrustManager#reportRequireCredentialEntry(int) 1167 */ requireCredentialEntry(int userId)1168 public void requireCredentialEntry(int userId) { 1169 getTrustManager().reportRequireCredentialEntry(userId); 1170 } 1171 onAfterChangingPassword(int userHandle)1172 private void onAfterChangingPassword(int userHandle) { 1173 getTrustManager().reportEnabledTrustAgentsChanged(userHandle); 1174 } 1175 isCredentialRequiredToDecrypt(boolean defaultValue)1176 public boolean isCredentialRequiredToDecrypt(boolean defaultValue) { 1177 final int value = Settings.Global.getInt(mContentResolver, 1178 Settings.Global.REQUIRE_PASSWORD_TO_DECRYPT, -1); 1179 return value == -1 ? defaultValue : (value != 0); 1180 } 1181 setCredentialRequiredToDecrypt(boolean required)1182 public void setCredentialRequiredToDecrypt(boolean required) { 1183 if (ActivityManager.getCurrentUser() != UserHandle.USER_OWNER) { 1184 Log.w(TAG, "Only device owner may call setCredentialRequiredForDecrypt()"); 1185 return; 1186 } 1187 1188 if (isDeviceEncryptionEnabled()){ 1189 Settings.Global.putInt(mContext.getContentResolver(), 1190 Settings.Global.REQUIRE_PASSWORD_TO_DECRYPT, required ? 1 : 0); 1191 } 1192 } 1193 isDoNotAskCredentialsOnBootSet()1194 private boolean isDoNotAskCredentialsOnBootSet() { 1195 return mDevicePolicyManager.getDoNotAskCredentialsOnBoot(); 1196 } 1197 shouldEncryptWithCredentials(boolean defaultValue)1198 private boolean shouldEncryptWithCredentials(boolean defaultValue) { 1199 return isCredentialRequiredToDecrypt(defaultValue) && !isDoNotAskCredentialsOnBootSet(); 1200 } 1201 } 1202