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