Home | History | Annotate | Download | only in widget
      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;
    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          */
    147         public int getTimeoutMs() {
    148             return mTimeoutMs;
    149         }
    150 
    151     }
    152 
    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 
    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 
    174     public LockPatternUtils(Context context) {
    175         mContext = context;
    176         mContentResolver = context.getContentResolver();
    177     }
    178 
    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 
    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      */
    196     public int getRequestedPasswordQuality(int userId) {
    197         return getDevicePolicyManager().getPasswordQuality(null, userId);
    198     }
    199 
    200     private int getRequestedPasswordHistoryLength(int userId) {
    201         return getDevicePolicyManager().getPasswordHistoryLength(null, userId);
    202     }
    203 
    204     public int getRequestedPasswordMinimumLetters(int userId) {
    205         return getDevicePolicyManager().getPasswordMinimumLetters(null, userId);
    206     }
    207 
    208     public int getRequestedPasswordMinimumUpperCase(int userId) {
    209         return getDevicePolicyManager().getPasswordMinimumUpperCase(null, userId);
    210     }
    211 
    212     public int getRequestedPasswordMinimumLowerCase(int userId) {
    213         return getDevicePolicyManager().getPasswordMinimumLowerCase(null, userId);
    214     }
    215 
    216     public int getRequestedPasswordMinimumNumeric(int userId) {
    217         return getDevicePolicyManager().getPasswordMinimumNumeric(null, userId);
    218     }
    219 
    220     public int getRequestedPasswordMinimumSymbols(int userId) {
    221         return getDevicePolicyManager().getPasswordMinimumSymbols(null, userId);
    222     }
    223 
    224     public int getRequestedPasswordMinimumNonLetter(int userId) {
    225         return getDevicePolicyManager().getPasswordMinimumNonLetter(null, userId);
    226     }
    227 
    228     public void reportFailedPasswordAttempt(int userId) {
    229         getDevicePolicyManager().reportFailedPasswordAttempt(userId);
    230         getTrustManager().reportUnlockAttempt(false /* authenticated */, userId);
    231         getTrustManager().reportRequireCredentialEntry(userId);
    232     }
    233 
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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 
    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 
    554     public void setOwnerInfo(String info, int userId) {
    555         setString(LOCK_SCREEN_OWNER_INFO, info, userId);
    556         updateCryptoUserInfo(userId);
    557     }
    558 
    559     public void setOwnerInfoEnabled(boolean enabled, int userId) {
    560         setBoolean(LOCK_SCREEN_OWNER_INFO_ENABLED, enabled, userId);
    561         updateCryptoUserInfo(userId);
    562     }
    563 
    564     public String getOwnerInfo(int userId) {
    565         return getString(LOCK_SCREEN_OWNER_INFO, userId);
    566     }
    567 
    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      */
    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 
    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 
    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      */
    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 **/
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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 
    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      */
    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 
    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      */
    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      */
    959     public boolean isSecure(int userId) {
    960         int mode = getKeyguardStoredPasswordQuality(userId);
    961         return isLockPatternEnabled(mode, userId) || isLockPasswordEnabled(mode, userId);
    962     }
    963 
    964     public boolean isLockPasswordEnabled(int userId) {
    965         return isLockPasswordEnabled(getKeyguardStoredPasswordQuality(userId), userId);
    966     }
    967 
    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      */
    980     public boolean isLockPatternEnabled(int userId) {
    981         return isLockPatternEnabled(getKeyguardStoredPasswordQuality(userId), userId);
    982     }
    983 
    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      */
    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      */
    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      */
   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      */
   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      */
   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      */
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   1130     public void setPowerButtonInstantlyLocks(boolean enabled, int userId) {
   1131         setBoolean(LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS, enabled, userId);
   1132     }
   1133 
   1134     public boolean getPowerButtonInstantlyLocks(int userId) {
   1135         return getBoolean(LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS, true, userId);
   1136     }
   1137 
   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 
   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      */
   1168     public void requireCredentialEntry(int userId) {
   1169         getTrustManager().reportRequireCredentialEntry(userId);
   1170     }
   1171 
   1172     private void onAfterChangingPassword(int userHandle) {
   1173         getTrustManager().reportEnabledTrustAgentsChanged(userHandle);
   1174     }
   1175 
   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 
   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 
   1194     private boolean isDoNotAskCredentialsOnBootSet() {
   1195         return mDevicePolicyManager.getDoNotAskCredentialsOnBoot();
   1196     }
   1197 
   1198     private boolean shouldEncryptWithCredentials(boolean defaultValue) {
   1199         return isCredentialRequiredToDecrypt(defaultValue) && !isDoNotAskCredentialsOnBootSet();
   1200     }
   1201 }
   1202