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