blob: 123d1ac21b97c721bca177edba420a2461758f6a [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.internal.widget;
18
Jim Miller78c48f62013-03-01 15:28:33 -080019import android.Manifest;
Amith Yamasani4b4b9542012-09-14 13:36:29 -070020import android.app.ActivityManagerNative;
Dianne Hackborn87bba1e2010-02-26 17:25:54 -080021import android.app.admin.DevicePolicyManager;
Adrian Roos82142c22014-03-27 14:56:59 +010022import android.app.trust.TrustManager;
Adrian Roos82142c22014-03-27 14:56:59 +010023import android.content.ComponentName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080024import android.content.ContentResolver;
Jim Miller31f90b62010-01-20 13:35:20 -080025import android.content.Context;
Danielle Millett58396982011-09-30 13:55:07 -040026import android.content.pm.PackageManager;
Adam Lesinski61d94092014-09-15 15:27:19 -070027import android.content.pm.UserInfo;
Paul Lawrence3a5a0be2014-09-25 09:26:34 -070028import android.os.AsyncTask;
Jason parksf7b3cd42011-01-27 09:28:25 -060029import android.os.IBinder;
Jim Miller69ac9882010-02-24 15:35:05 -080030import android.os.RemoteException;
31import android.os.ServiceManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080032import android.os.SystemClock;
Jim Miller6848dc82014-10-13 18:51:53 -070033import android.os.SystemProperties;
Dianne Hackbornf02b60a2012-08-16 10:48:27 -070034import android.os.UserHandle;
Adam Lesinski61d94092014-09-15 15:27:19 -070035import android.os.UserManager;
Jason parksf7b3cd42011-01-27 09:28:25 -060036import android.os.storage.IMountService;
Paul Lawrence8e397362014-01-27 15:22:30 -080037import android.os.storage.StorageManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080038import android.provider.Settings;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080039import android.text.TextUtils;
40import android.util.Log;
41
Michael Jurka1254f2f2012-10-25 11:44:31 -070042import com.google.android.collect.Lists;
Adrian Roos9dd16eb2015-01-08 16:20:49 +010043
Narayan Kamath78108a32014-12-16 12:56:23 +000044import java.nio.charset.StandardCharsets;
Brian Carlstrom929a1c22011-02-01 21:54:09 -080045import java.security.MessageDigest;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080046import java.security.NoSuchAlgorithmException;
Jim Miller11b019d2010-01-20 16:34:45 -080047import java.security.SecureRandom;
Adrian Roos82142c22014-03-27 14:56:59 +010048import java.util.ArrayList;
49import java.util.Collection;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080050import java.util.List;
51
Adrian Roosc2e01682015-01-15 23:20:20 +010052import libcore.util.HexEncoding;
53
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080054/**
Brian Carlstrom5cfee3f2011-05-31 01:00:15 -070055 * Utilities for the lock pattern and its settings.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080056 */
57public class LockPatternUtils {
58
59 private static final String TAG = "LockPatternUtils";
Brian Colonnaa0ee0042014-07-16 13:50:47 -040060 private static final boolean DEBUG = false;
Jim Miller69aa4a92009-12-22 19:03:28 -080061
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080062 /**
63 * The maximum number of incorrect attempts before the user is prevented
64 * from trying again for {@link #FAILED_ATTEMPT_TIMEOUT_MS}.
65 */
66 public static final int FAILED_ATTEMPTS_BEFORE_TIMEOUT = 5;
67
68 /**
69 * The number of incorrect attempts before which we fall back on an alternative
70 * method of verifying the user, and resetting their lock pattern.
71 */
72 public static final int FAILED_ATTEMPTS_BEFORE_RESET = 20;
73
74 /**
75 * How long the user is prevented from trying again after entering the
76 * wrong pattern too many times.
77 */
78 public static final long FAILED_ATTEMPT_TIMEOUT_MS = 30000L;
79
80 /**
81 * The interval of the countdown for showing progress of the lockout.
82 */
83 public static final long FAILED_ATTEMPT_COUNTDOWN_INTERVAL_MS = 1000L;
84
Jim Miller4f369952011-08-19 18:29:22 -070085
86 /**
87 * This dictates when we start telling the user that continued failed attempts will wipe
88 * their device.
89 */
90 public static final int FAILED_ATTEMPTS_BEFORE_WIPE_GRACE = 5;
91
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080092 /**
93 * The minimum number of dots in a valid pattern.
94 */
95 public static final int MIN_LOCK_PATTERN_SIZE = 4;
96
97 /**
Adrian Roosf80e66ce92015-01-15 23:27:24 +010098 * The minimum size of a valid password.
99 */
100 public static final int MIN_LOCK_PASSWORD_SIZE = 4;
101
102 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800103 * The minimum number of dots the user must include in a wrong pattern
104 * attempt for it to be counted against the counts that affect
105 * {@link #FAILED_ATTEMPTS_BEFORE_TIMEOUT} and {@link #FAILED_ATTEMPTS_BEFORE_RESET}
106 */
Jim Miller4f369952011-08-19 18:29:22 -0700107 public static final int MIN_PATTERN_REGISTER_FAIL = MIN_LOCK_PATTERN_SIZE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800108
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100109 @Deprecated
Jeff Sharkey7a96c392012-11-15 14:01:46 -0800110 public final static String LOCKOUT_PERMANENT_KEY = "lockscreen.lockedoutpermanently";
111 public final static String LOCKOUT_ATTEMPT_DEADLINE = "lockscreen.lockoutattemptdeadline";
112 public final static String PATTERN_EVER_CHOSEN_KEY = "lockscreen.patterneverchosen";
Jim Miller69aa4a92009-12-22 19:03:28 -0800113 public final static String PASSWORD_TYPE_KEY = "lockscreen.password_type";
Adrian Roos230635e2015-01-07 20:50:29 +0100114 @Deprecated
115 public final static String PASSWORD_TYPE_ALTERNATE_KEY = "lockscreen.password_type_alternate";
Jeff Sharkey7a96c392012-11-15 14:01:46 -0800116 public final static String LOCK_PASSWORD_SALT_KEY = "lockscreen.password_salt";
117 public final static String DISABLE_LOCKSCREEN_KEY = "lockscreen.disabled";
118 public final static String LOCKSCREEN_OPTIONS = "lockscreen.options";
Adrian Roos230635e2015-01-07 20:50:29 +0100119 @Deprecated
Jim Miller6edf2632011-09-05 16:03:14 -0700120 public final static String LOCKSCREEN_BIOMETRIC_WEAK_FALLBACK
121 = "lockscreen.biometric_weak_fallback";
Adrian Roos230635e2015-01-07 20:50:29 +0100122 @Deprecated
Danielle Millett7a072192011-10-03 17:36:01 -0400123 public final static String BIOMETRIC_WEAK_EVER_CHOSEN_KEY
124 = "lockscreen.biometricweakeverchosen";
Jim Millera4edd152012-01-06 18:24:04 -0800125 public final static String LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS
126 = "lockscreen.power_button_instantly_locks";
Adrian Roos230635e2015-01-07 20:50:29 +0100127 @Deprecated
Jim Millerf45bb402013-08-20 18:58:32 -0700128 public final static String LOCKSCREEN_WIDGETS_ENABLED = "lockscreen.widgets_enabled";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800129
Jeff Sharkey7a96c392012-11-15 14:01:46 -0800130 public final static String PASSWORD_HISTORY_KEY = "lockscreen.passwordhistory";
Konstantin Lopyrev863f22d2010-05-12 17:16:58 -0700131
Jim Miller187ec582013-04-15 18:27:54 -0700132 private static final String LOCK_SCREEN_OWNER_INFO = Settings.Secure.LOCK_SCREEN_OWNER_INFO;
133 private static final String LOCK_SCREEN_OWNER_INFO_ENABLED =
134 Settings.Secure.LOCK_SCREEN_OWNER_INFO_ENABLED;
135
Adrian Roos82142c22014-03-27 14:56:59 +0100136 private static final String ENABLED_TRUST_AGENTS = "lockscreen.enabledtrustagents";
137
Jim Miller85516d02014-01-31 17:08:37 -0800138 // Maximum allowed number of repeated or ordered characters in a sequence before we'll
139 // consider it a complex PIN/password.
140 public static final int MAX_ALLOWED_SEQUENCE = 3;
141
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800142 private final Context mContext;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800143 private final ContentResolver mContentResolver;
Jim Miller31f90b62010-01-20 13:35:20 -0800144 private DevicePolicyManager mDevicePolicyManager;
Amith Yamasani52c489c2012-03-28 11:42:42 -0700145 private ILockSettings mLockSettingsService;
Jim Milleree82f8f2012-10-01 16:26:18 -0700146
Jim Miller78c48f62013-03-01 15:28:33 -0800147 private final boolean mMultiUserMode;
148
Jim Milleree82f8f2012-10-01 16:26:18 -0700149 // The current user is set by KeyguardViewMediator and shared by all LockPatternUtils.
150 private static volatile int sCurrentUserId = UserHandle.USER_NULL;
Dianne Hackbornde4c26f2011-07-17 13:42:47 -0700151
Jim Millercd709882010-03-25 18:24:02 -0700152 public DevicePolicyManager getDevicePolicyManager() {
Jim Miller5b0fb3a2010-02-23 13:46:35 -0800153 if (mDevicePolicyManager == null) {
154 mDevicePolicyManager =
155 (DevicePolicyManager)mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
156 if (mDevicePolicyManager == null) {
157 Log.e(TAG, "Can't get DevicePolicyManagerService: is it running?",
158 new IllegalStateException("Stack trace:"));
159 }
160 }
161 return mDevicePolicyManager;
162 }
Amith Yamasani52c489c2012-03-28 11:42:42 -0700163
Adrian Roos82142c22014-03-27 14:56:59 +0100164 private TrustManager getTrustManager() {
165 TrustManager trust = (TrustManager) mContext.getSystemService(Context.TRUST_SERVICE);
166 if (trust == null) {
167 Log.e(TAG, "Can't get TrustManagerService: is it running?",
168 new IllegalStateException("Stack trace:"));
169 }
170 return trust;
171 }
172
Jim Miller31f90b62010-01-20 13:35:20 -0800173 public LockPatternUtils(Context context) {
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800174 mContext = context;
Jim Miller31f90b62010-01-20 13:35:20 -0800175 mContentResolver = context.getContentResolver();
Jim Miller78c48f62013-03-01 15:28:33 -0800176
177 // If this is being called by the system or by an application like keyguard that
178 // has permision INTERACT_ACROSS_USERS, then LockPatternUtils will operate in multi-user
179 // mode where calls are for the current user rather than the user of the calling process.
180 mMultiUserMode = context.checkCallingOrSelfPermission(
181 Manifest.permission.INTERACT_ACROSS_USERS_FULL) == PackageManager.PERMISSION_GRANTED;
Amith Yamasani52c489c2012-03-28 11:42:42 -0700182 }
Jim Miller69aa4a92009-12-22 19:03:28 -0800183
Amith Yamasani52c489c2012-03-28 11:42:42 -0700184 private ILockSettings getLockSettings() {
185 if (mLockSettingsService == null) {
Adrian Roos450ce9f2014-10-29 14:30:37 +0100186 ILockSettings service = ILockSettings.Stub.asInterface(
187 ServiceManager.getService("lock_settings"));
Adrian Roos138b8332014-11-11 13:51:07 +0100188 mLockSettingsService = service;
Brad Fitzpatrick90881002010-08-23 18:30:08 -0700189 }
Amith Yamasani52c489c2012-03-28 11:42:42 -0700190 return mLockSettingsService;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800191 }
192
Jim Miller31f90b62010-01-20 13:35:20 -0800193 public int getRequestedMinimumPasswordLength() {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700194 return getDevicePolicyManager().getPasswordMinimumLength(null, getCurrentOrCallingUserId());
Jim Miller31f90b62010-01-20 13:35:20 -0800195 }
196
Jim Miller31f90b62010-01-20 13:35:20 -0800197 /**
198 * Gets the device policy password mode. If the mode is non-specific, returns
199 * MODE_PATTERN which allows the user to choose anything.
Jim Miller31f90b62010-01-20 13:35:20 -0800200 */
Jim Millercd709882010-03-25 18:24:02 -0700201 public int getRequestedPasswordQuality() {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700202 return getDevicePolicyManager().getPasswordQuality(null, getCurrentOrCallingUserId());
Jim Miller31f90b62010-01-20 13:35:20 -0800203 }
204
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700205 public int getRequestedPasswordHistoryLength() {
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100206 return getRequestedPasswordHistoryLength(getCurrentOrCallingUserId());
207 }
208
209 private int getRequestedPasswordHistoryLength(int userId) {
210 return getDevicePolicyManager().getPasswordHistoryLength(null, userId);
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700211 }
212
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700213 public int getRequestedPasswordMinimumLetters() {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700214 return getDevicePolicyManager().getPasswordMinimumLetters(null,
215 getCurrentOrCallingUserId());
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700216 }
217
218 public int getRequestedPasswordMinimumUpperCase() {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700219 return getDevicePolicyManager().getPasswordMinimumUpperCase(null,
220 getCurrentOrCallingUserId());
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700221 }
222
223 public int getRequestedPasswordMinimumLowerCase() {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700224 return getDevicePolicyManager().getPasswordMinimumLowerCase(null,
225 getCurrentOrCallingUserId());
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700226 }
227
228 public int getRequestedPasswordMinimumNumeric() {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700229 return getDevicePolicyManager().getPasswordMinimumNumeric(null,
230 getCurrentOrCallingUserId());
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700231 }
232
233 public int getRequestedPasswordMinimumSymbols() {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700234 return getDevicePolicyManager().getPasswordMinimumSymbols(null,
235 getCurrentOrCallingUserId());
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700236 }
237
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700238 public int getRequestedPasswordMinimumNonLetter() {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700239 return getDevicePolicyManager().getPasswordMinimumNonLetter(null,
240 getCurrentOrCallingUserId());
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700241 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700242
Jim Miller31f90b62010-01-20 13:35:20 -0800243 public void reportFailedPasswordAttempt() {
Adrian Roos4f994eb2014-07-23 15:45:05 +0200244 int userId = getCurrentOrCallingUserId();
245 getDevicePolicyManager().reportFailedPasswordAttempt(userId);
246 getTrustManager().reportUnlockAttempt(false /* authenticated */, userId);
247 getTrustManager().reportRequireCredentialEntry(userId);
Jim Miller31f90b62010-01-20 13:35:20 -0800248 }
249
250 public void reportSuccessfulPasswordAttempt() {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700251 getDevicePolicyManager().reportSuccessfulPasswordAttempt(getCurrentOrCallingUserId());
Adrian Roos82142c22014-03-27 14:56:59 +0100252 getTrustManager().reportUnlockAttempt(true /* authenticated */,
253 getCurrentOrCallingUserId());
Jim Miller31f90b62010-01-20 13:35:20 -0800254 }
255
Amith Yamasani52c489c2012-03-28 11:42:42 -0700256 public void setCurrentUser(int userId) {
Jim Milleree82f8f2012-10-01 16:26:18 -0700257 sCurrentUserId = userId;
Amith Yamasani52c489c2012-03-28 11:42:42 -0700258 }
259
Amith Yamasanif882f1a2012-04-10 15:13:39 -0700260 public int getCurrentUser() {
Jim Milleree82f8f2012-10-01 16:26:18 -0700261 if (sCurrentUserId != UserHandle.USER_NULL) {
Jim Miller25645d82012-09-21 14:47:54 -0700262 // Someone is regularly updating using setCurrentUser() use that value.
Jim Milleree82f8f2012-10-01 16:26:18 -0700263 return sCurrentUserId;
Jim Miller25645d82012-09-21 14:47:54 -0700264 }
265 try {
266 return ActivityManagerNative.getDefault().getCurrentUser().id;
267 } catch (RemoteException re) {
268 return UserHandle.USER_OWNER;
Amith Yamasanif882f1a2012-04-10 15:13:39 -0700269 }
270 }
271
Amith Yamasani52c489c2012-03-28 11:42:42 -0700272 private int getCurrentOrCallingUserId() {
Jim Miller78c48f62013-03-01 15:28:33 -0800273 if (mMultiUserMode) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700274 // TODO: This is a little inefficient. See if all users of this are able to
275 // handle USER_CURRENT and pass that instead.
276 return getCurrentUser();
Amith Yamasani52c489c2012-03-28 11:42:42 -0700277 } else {
Jim Miller78c48f62013-03-01 15:28:33 -0800278 return UserHandle.getCallingUserId();
Amith Yamasani52c489c2012-03-28 11:42:42 -0700279 }
280 }
281
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800282 /**
Andres Moralesd9fc85a2015-04-09 19:14:42 -0700283 * Check to see if a pattern matches the saved pattern.
284 * If pattern matches, return an opaque attestation that the challenge
285 * was verified.
286 *
287 * @param pattern The pattern to check.
288 * @param challenge The challenge to verify against the pattern
289 * @return the attestation that the challenge was verified, or null.
290 */
291 public byte[] verifyPattern(List<LockPatternView.Cell> pattern, long challenge) {
292 final int userId = getCurrentOrCallingUserId();
293 try {
294 return getLockSettings().verifyPattern(patternToString(pattern), challenge, userId);
295 } catch (RemoteException re) {
296 return null;
297 }
298 }
299
300 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800301 * Check to see if a pattern matches the saved pattern. If no pattern exists,
302 * always returns true.
303 * @param pattern The pattern to check.
Jim Miller69aa4a92009-12-22 19:03:28 -0800304 * @return Whether the pattern matches the stored one.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800305 */
306 public boolean checkPattern(List<LockPatternView.Cell> pattern) {
Kenny Rootdf8bfe02012-09-21 15:00:25 -0700307 final int userId = getCurrentOrCallingUserId();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800308 try {
Jim Millerde1af082013-09-11 14:58:26 -0700309 return getLockSettings().checkPattern(patternToString(pattern), userId);
Amith Yamasani52c489c2012-03-28 11:42:42 -0700310 } catch (RemoteException re) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800311 return true;
312 }
313 }
314
315 /**
Andres Moralesd9fc85a2015-04-09 19:14:42 -0700316 * Check to see if a password matches the saved password.
317 * If password matches, return an opaque attestation that the challenge
318 * was verified.
319 *
320 * @param password The password to check.
321 * @param challenge The challenge to verify against the password
322 * @return the attestation that the challenge was verified, or null.
323 */
324 public byte[] verifyPassword(String password, long challenge) {
325 final int userId = getCurrentOrCallingUserId();
326 try {
327 return getLockSettings().verifyPassword(password, challenge, userId);
328 } catch (RemoteException re) {
329 return null;
330 }
331 }
332
333 /**
Jim Miller69aa4a92009-12-22 19:03:28 -0800334 * Check to see if a password matches the saved password. If no password exists,
335 * always returns true.
336 * @param password The password to check.
337 * @return Whether the password matches the stored one.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800338 */
Jim Miller69aa4a92009-12-22 19:03:28 -0800339 public boolean checkPassword(String password) {
Kenny Rootdf8bfe02012-09-21 15:00:25 -0700340 final int userId = getCurrentOrCallingUserId();
Jim Miller69aa4a92009-12-22 19:03:28 -0800341 try {
Jim Millerde1af082013-09-11 14:58:26 -0700342 return getLockSettings().checkPassword(password, userId);
Amith Yamasani52c489c2012-03-28 11:42:42 -0700343 } catch (RemoteException re) {
Jim Miller69aa4a92009-12-22 19:03:28 -0800344 return true;
345 }
346 }
347
348 /**
Paul Lawrence945490c2014-03-27 16:37:28 +0000349 * Check to see if vold already has the password.
350 * Note that this also clears vold's copy of the password.
351 * @return Whether the vold password matches or not.
352 */
353 public boolean checkVoldPassword() {
354 final int userId = getCurrentOrCallingUserId();
355 try {
356 return getLockSettings().checkVoldPassword(userId);
357 } catch (RemoteException re) {
358 return false;
359 }
360 }
361
362 /**
Konstantin Lopyrev863f22d2010-05-12 17:16:58 -0700363 * Check to see if a password matches any of the passwords stored in the
364 * password history.
365 *
366 * @param password The password to check.
367 * @return Whether the password matches any in the history.
368 */
369 public boolean checkPasswordHistory(String password) {
Adrian Roosdce01222015-01-07 22:39:01 +0100370 int userId = getCurrentOrCallingUserId();
Geoffrey Borggaard987672d22014-07-18 16:47:18 -0400371 String passwordHashString = new String(
Adrian Roosdce01222015-01-07 22:39:01 +0100372 passwordToHash(password, userId), StandardCharsets.UTF_8);
373 String passwordHistory = getString(PASSWORD_HISTORY_KEY, userId);
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700374 if (passwordHistory == null) {
375 return false;
376 }
377 // Password History may be too long...
378 int passwordHashLength = passwordHashString.length();
379 int passwordHistoryLength = getRequestedPasswordHistoryLength();
380 if(passwordHistoryLength == 0) {
381 return false;
382 }
383 int neededPasswordHistoryLength = passwordHashLength * passwordHistoryLength
384 + passwordHistoryLength - 1;
385 if (passwordHistory.length() > neededPasswordHistoryLength) {
386 passwordHistory = passwordHistory.substring(0, neededPasswordHistoryLength);
387 }
388 return passwordHistory.contains(passwordHashString);
Konstantin Lopyrev863f22d2010-05-12 17:16:58 -0700389 }
390
391 /**
Jim Miller69aa4a92009-12-22 19:03:28 -0800392 * Check to see if the user has stored a lock pattern.
393 * @return Whether a saved pattern exists.
394 */
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100395 private boolean savedPatternExists(int userId) {
Amith Yamasani52c489c2012-03-28 11:42:42 -0700396 try {
Adrian Roos50bfeec2014-11-20 16:21:11 +0100397 return getLockSettings().havePattern(userId);
Amith Yamasani52c489c2012-03-28 11:42:42 -0700398 } catch (RemoteException re) {
399 return false;
400 }
Jim Miller69aa4a92009-12-22 19:03:28 -0800401 }
402
403 /**
404 * Check to see if the user has stored a lock pattern.
405 * @return Whether a saved pattern exists.
406 */
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100407 private boolean savedPasswordExists(int userId) {
Amith Yamasani52c489c2012-03-28 11:42:42 -0700408 try {
Adrian Roos50bfeec2014-11-20 16:21:11 +0100409 return getLockSettings().havePassword(userId);
Amith Yamasani52c489c2012-03-28 11:42:42 -0700410 } catch (RemoteException re) {
411 return false;
412 }
Jim Miller69aa4a92009-12-22 19:03:28 -0800413 }
414
415 /**
The Android Open Source Projectba87e3e2009-03-13 13:04:22 -0700416 * Return true if the user has ever chosen a pattern. This is true even if the pattern is
417 * currently cleared.
418 *
419 * @return True if the user has ever chosen a pattern.
420 */
421 public boolean isPatternEverChosen() {
Adrian Roosdce01222015-01-07 22:39:01 +0100422 return getBoolean(PATTERN_EVER_CHOSEN_KEY, false, getCurrentOrCallingUserId());
The Android Open Source Projectba87e3e2009-03-13 13:04:22 -0700423 }
424
425 /**
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700426 * Used by device policy manager to validate the current password
427 * information it has.
428 */
429 public int getActivePasswordQuality() {
Adrian Roosdce01222015-01-07 22:39:01 +0100430 return getActivePasswordQuality(getCurrentOrCallingUserId());
431 }
432
433 /**
434 * Used by device policy manager to validate the current password
435 * information it has.
436 */
437 public int getActivePasswordQuality(int userId) {
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100438 int quality = getKeyguardStoredPasswordQuality(userId);
Adrian Roosdce01222015-01-07 22:39:01 +0100439
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100440 if (isLockPasswordEnabled(quality, userId)) {
441 // Quality is a password and a password exists. Return the quality.
442 return quality;
443 }
444
445 if (isLockPatternEnabled(quality, userId)) {
446 // Quality is a pattern and a pattern exists. Return the quality.
447 return quality;
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700448 }
Danielle Millettc8fb5322011-10-04 12:18:51 -0400449
Adrian Roosdce01222015-01-07 22:39:01 +0100450 return DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700451 }
Jim Millercd709882010-03-25 18:24:02 -0700452
Adrian Roos230635e2015-01-07 20:50:29 +0100453 public void clearLock() {
454 clearLock(getCurrentOrCallingUserId());
Adrian Roosf8f56bc2014-11-20 23:55:34 +0100455 }
456
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700457 /**
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800458 * Clear any lock pattern or password.
459 */
Adrian Roos230635e2015-01-07 20:50:29 +0100460 public void clearLock(int userHandle) {
Adrian Roosf8f56bc2014-11-20 23:55:34 +0100461 setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, userHandle);
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100462
463 try {
Andres Morales8fa56652015-03-31 09:19:50 -0700464 getLockSettings().setLockPassword(null, null, userHandle);
465 getLockSettings().setLockPattern(null, null, userHandle);
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100466 } catch (RemoteException e) {
467 // well, we tried...
468 }
469
470 if (userHandle == UserHandle.USER_OWNER) {
471 // Set the encryption password to default.
472 updateEncryptionPassword(StorageManager.CRYPT_TYPE_DEFAULT, null);
473 }
474
475 getDevicePolicyManager().setActivePasswordState(
476 DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, 0, 0, 0, 0, 0, 0, 0, userHandle);
477
Adrian Roosf8f56bc2014-11-20 23:55:34 +0100478 onAfterChangingPassword(userHandle);
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800479 }
Jim Miller5b0fb3a2010-02-23 13:46:35 -0800480
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800481 /**
Jim Miller2a98a4c2010-11-19 18:49:26 -0800482 * Disable showing lock screen at all when the DevicePolicyManager allows it.
483 * This is only meaningful if pattern, pin or password are not set.
484 *
485 * @param disable Disables lock screen when true
486 */
487 public void setLockScreenDisabled(boolean disable) {
Benjamin Franz51ed7942015-04-07 16:34:56 +0100488 setLockScreenDisabled(disable, getCurrentOrCallingUserId());
Jim Miller2a98a4c2010-11-19 18:49:26 -0800489 }
490
491 /**
Benjamin Franz51ed7942015-04-07 16:34:56 +0100492 * Disable showing lock screen at all for a given user.
493 * This is only meaningful if pattern, pin or password are not set.
Jim Miller2a98a4c2010-11-19 18:49:26 -0800494 *
Benjamin Franz51ed7942015-04-07 16:34:56 +0100495 * @param disable Disables lock screen when true
496 * @param userId User ID of the user this has effect on
497 */
498 public void setLockScreenDisabled(boolean disable, int userId) {
499 setBoolean(DISABLE_LOCKSCREEN_KEY, disable, userId);
500 }
501
502 /**
503 * Determine if LockScreen is disabled for the current user. This is used to decide whether
504 * LockScreen is shown after reboot or after screen timeout / short press on power.
505 *
506 * @return true if lock screen is disabled
Jim Miller2a98a4c2010-11-19 18:49:26 -0800507 */
508 public boolean isLockScreenDisabled() {
Benjamin Franz51ed7942015-04-07 16:34:56 +0100509 return !isSecure() &&
510 getBoolean(DISABLE_LOCKSCREEN_KEY, false, getCurrentOrCallingUserId());
Jim Miller2a98a4c2010-11-19 18:49:26 -0800511 }
512
513 /**
Jim Miller6edf2632011-09-05 16:03:14 -0700514 * Save a lock pattern.
515 * @param pattern The new pattern to save.
Andres Morales8fa56652015-03-31 09:19:50 -0700516 * @param savedPattern The previously saved pattern, or null if none
Danielle Millett2364a222011-12-21 17:02:32 -0500517 */
Andres Morales8fa56652015-03-31 09:19:50 -0700518 public void saveLockPattern(List<LockPatternView.Cell> pattern,
519 String savedPattern) {
520 this.saveLockPattern(pattern, savedPattern, getCurrentOrCallingUserId());
Danielle Millett2364a222011-12-21 17:02:32 -0500521 }
522
Andres Morales8fa56652015-03-31 09:19:50 -0700523 public void saveLockPattern(List<LockPatternView.Cell> pattern, int userId) {
524 this.saveLockPattern(pattern, null, userId);
525 }
Danielle Millett2364a222011-12-21 17:02:32 -0500526 /**
527 * Save a lock pattern.
528 * @param pattern The new pattern to save.
Andres Morales8fa56652015-03-31 09:19:50 -0700529 * @param savedPattern The previously saved pattern, converted to String format
Adrian Roosf8f56bc2014-11-20 23:55:34 +0100530 * @param userId the user whose pattern is to be saved.
531 */
Andres Morales8fa56652015-03-31 09:19:50 -0700532 public void saveLockPattern(List<LockPatternView.Cell> pattern, String savedPattern, int userId) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800533 try {
Adrian Roosf80e66ce92015-01-15 23:27:24 +0100534 if (pattern == null || pattern.size() < MIN_LOCK_PATTERN_SIZE) {
535 throw new IllegalArgumentException("pattern must not be null and at least "
536 + MIN_LOCK_PATTERN_SIZE + " dots long.");
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100537 }
538
Andres Morales8fa56652015-03-31 09:19:50 -0700539 getLockSettings().setLockPattern(patternToString(pattern), savedPattern, userId);
Dianne Hackborn2509d3c2010-03-08 12:54:25 -0800540 DevicePolicyManager dpm = getDevicePolicyManager();
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100541
542 // Update the device encryption password.
543 if (userId == UserHandle.USER_OWNER
544 && LockPatternUtils.isDeviceEncryptionEnabled()) {
545 final boolean required = isCredentialRequiredToDecrypt(true);
546 if (!required) {
547 clearEncryptionPassword();
548 } else {
549 String stringPattern = patternToString(pattern);
550 updateEncryptionPassword(StorageManager.CRYPT_TYPE_PATTERN, stringPattern);
Paul Lawrence8e397362014-01-27 15:22:30 -0800551 }
Jim Miller31f90b62010-01-20 13:35:20 -0800552 }
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100553
554 setBoolean(PATTERN_EVER_CHOSEN_KEY, true, userId);
555
556 setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING, userId);
557 dpm.setActivePasswordState(DevicePolicyManager.PASSWORD_QUALITY_SOMETHING,
558 pattern.size(), 0, 0, 0, 0, 0, 0, userId);
Adrian Roosf8f56bc2014-11-20 23:55:34 +0100559 onAfterChangingPassword(userId);
Amith Yamasani52c489c2012-03-28 11:42:42 -0700560 } catch (RemoteException re) {
561 Log.e(TAG, "Couldn't save lock pattern " + re);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800562 }
563 }
564
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100565 private void updateCryptoUserInfo(int userId) {
Paul Lawrencee51dcf92014-03-18 10:56:00 -0700566 if (userId != UserHandle.USER_OWNER) {
567 return;
568 }
569
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100570 final String ownerInfo = isOwnerInfoEnabled(userId) ? getOwnerInfo(userId) : "";
Paul Lawrencee51dcf92014-03-18 10:56:00 -0700571
572 IBinder service = ServiceManager.getService("mount");
573 if (service == null) {
574 Log.e(TAG, "Could not find the mount service to update the user info");
575 return;
576 }
577
578 IMountService mountService = IMountService.Stub.asInterface(service);
579 try {
580 Log.d(TAG, "Setting owner info");
Elliott Hughesf839b4f2014-09-26 12:30:47 -0700581 mountService.setField(StorageManager.OWNER_INFO_KEY, ownerInfo);
Paul Lawrencee51dcf92014-03-18 10:56:00 -0700582 } catch (RemoteException e) {
583 Log.e(TAG, "Error changing user info", e);
584 }
585 }
586
Jim Miller187ec582013-04-15 18:27:54 -0700587 public void setOwnerInfo(String info, int userId) {
588 setString(LOCK_SCREEN_OWNER_INFO, info, userId);
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100589 updateCryptoUserInfo(userId);
Jim Miller187ec582013-04-15 18:27:54 -0700590 }
591
592 public void setOwnerInfoEnabled(boolean enabled) {
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100593 int userId = getCurrentOrCallingUserId();
594 setBoolean(LOCK_SCREEN_OWNER_INFO_ENABLED, enabled, userId);
595 updateCryptoUserInfo(userId);
Jim Miller187ec582013-04-15 18:27:54 -0700596 }
597
598 public String getOwnerInfo(int userId) {
Adrian Roosdce01222015-01-07 22:39:01 +0100599 return getString(LOCK_SCREEN_OWNER_INFO, userId);
Jim Miller187ec582013-04-15 18:27:54 -0700600 }
601
602 public boolean isOwnerInfoEnabled() {
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100603 return isOwnerInfoEnabled(getCurrentOrCallingUserId());
604 }
605
606 private boolean isOwnerInfoEnabled(int userId) {
607 return getBoolean(LOCK_SCREEN_OWNER_INFO_ENABLED, false, userId);
Jim Miller187ec582013-04-15 18:27:54 -0700608 }
609
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800610 /**
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700611 * Compute the password quality from the given password string.
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800612 */
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700613 static public int computePasswordQuality(String password) {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800614 boolean hasDigit = false;
615 boolean hasNonDigit = false;
616 final int len = password.length();
617 for (int i = 0; i < len; i++) {
618 if (Character.isDigit(password.charAt(i))) {
619 hasDigit = true;
620 } else {
621 hasNonDigit = true;
622 }
623 }
Jim Miller5b0fb3a2010-02-23 13:46:35 -0800624
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700625 if (hasNonDigit && hasDigit) {
626 return DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC;
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800627 }
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800628 if (hasNonDigit) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700629 return DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC;
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800630 }
631 if (hasDigit) {
Jim Miller85516d02014-01-31 17:08:37 -0800632 return maxLengthSequence(password) > MAX_ALLOWED_SEQUENCE
633 ? DevicePolicyManager.PASSWORD_QUALITY_NUMERIC
634 : DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX;
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800635 }
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700636 return DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800637 }
Jim Miller5b0fb3a2010-02-23 13:46:35 -0800638
Jim Miller85516d02014-01-31 17:08:37 -0800639 private static int categoryChar(char c) {
640 if ('a' <= c && c <= 'z') return 0;
641 if ('A' <= c && c <= 'Z') return 1;
642 if ('0' <= c && c <= '9') return 2;
643 return 3;
644 }
645
646 private static int maxDiffCategory(int category) {
647 if (category == 0 || category == 1) return 1;
648 else if (category == 2) return 10;
649 return 0;
650 }
651
652 /*
653 * Returns the maximum length of a sequential characters. A sequence is defined as
654 * monotonically increasing characters with a constant interval or the same character repeated.
655 *
656 * For example:
657 * maxLengthSequence("1234") == 4
658 * maxLengthSequence("1234abc") == 4
659 * maxLengthSequence("aabc") == 3
660 * maxLengthSequence("qwertyuio") == 1
661 * maxLengthSequence("@ABC") == 3
662 * maxLengthSequence(";;;;") == 4 (anything that repeats)
663 * maxLengthSequence(":;<=>") == 1 (ordered, but not composed of alphas or digits)
664 *
665 * @param string the pass
666 * @return the number of sequential letters or digits
667 */
668 public static int maxLengthSequence(String string) {
669 if (string.length() == 0) return 0;
670 char previousChar = string.charAt(0);
671 int category = categoryChar(previousChar); //current category of the sequence
672 int diff = 0; //difference between two consecutive characters
673 boolean hasDiff = false; //if we are currently targeting a sequence
674 int maxLength = 0; //maximum length of a sequence already found
675 int startSequence = 0; //where the current sequence started
676 for (int current = 1; current < string.length(); current++) {
677 char currentChar = string.charAt(current);
678 int categoryCurrent = categoryChar(currentChar);
679 int currentDiff = (int) currentChar - (int) previousChar;
680 if (categoryCurrent != category || Math.abs(currentDiff) > maxDiffCategory(category)) {
681 maxLength = Math.max(maxLength, current - startSequence);
682 startSequence = current;
683 hasDiff = false;
684 category = categoryCurrent;
685 }
686 else {
687 if(hasDiff && currentDiff != diff) {
688 maxLength = Math.max(maxLength, current - startSequence);
689 startSequence = current - 1;
690 }
691 diff = currentDiff;
692 hasDiff = true;
693 }
694 previousChar = currentChar;
695 }
696 maxLength = Math.max(maxLength, string.length() - startSequence);
697 return maxLength;
698 }
699
Jason parksf7b3cd42011-01-27 09:28:25 -0600700 /** Update the encryption password if it is enabled **/
Paul Lawrence3a5a0be2014-09-25 09:26:34 -0700701 private void updateEncryptionPassword(final int type, final String password) {
Amith Yamasanicd410ba2014-10-17 11:16:58 -0700702 if (!isDeviceEncryptionEnabled()) {
Jason parksf7b3cd42011-01-27 09:28:25 -0600703 return;
704 }
Paul Lawrence3a5a0be2014-09-25 09:26:34 -0700705 final IBinder service = ServiceManager.getService("mount");
Jason parksf7b3cd42011-01-27 09:28:25 -0600706 if (service == null) {
707 Log.e(TAG, "Could not find the mount service to update the encryption password");
708 return;
709 }
710
Paul Lawrence3a5a0be2014-09-25 09:26:34 -0700711 new AsyncTask<Void, Void, Void>() {
712 @Override
713 protected Void doInBackground(Void... dummy) {
714 IMountService mountService = IMountService.Stub.asInterface(service);
715 try {
716 mountService.changeEncryptionPassword(type, password);
717 } catch (RemoteException e) {
718 Log.e(TAG, "Error changing encryption password", e);
719 }
720 return null;
721 }
722 }.execute();
Jason parksf7b3cd42011-01-27 09:28:25 -0600723 }
724
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800725 /**
Jim Millercd709882010-03-25 18:24:02 -0700726 * Save a lock password. Does not ensure that the password is as good
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800727 * as the requested mode, but will adjust the mode to be as good as the
728 * pattern.
Jim Miller69aa4a92009-12-22 19:03:28 -0800729 * @param password The password to save
Andres Morales8fa56652015-03-31 09:19:50 -0700730 * @param savedPassword The previously saved lock password, or null if none
Jim Millercd709882010-03-25 18:24:02 -0700731 * @param quality {@see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)}
Jim Miller69aa4a92009-12-22 19:03:28 -0800732 */
Andres Morales8fa56652015-03-31 09:19:50 -0700733 public void saveLockPassword(String password, String savedPassword, int quality) {
734 saveLockPassword(password, savedPassword, quality, getCurrentOrCallingUserId());
Jim Miller6edf2632011-09-05 16:03:14 -0700735 }
736
737 /**
738 * Save a lock password. Does not ensure that the password is as good
739 * as the requested mode, but will adjust the mode to be as good as the
740 * pattern.
741 * @param password The password to save
742 * @param quality {@see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)}
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700743 * @param userHandle The userId of the user to change the password for
744 */
Andres Morales8fa56652015-03-31 09:19:50 -0700745 public void saveLockPassword(String password, String savedPassword, int quality,
746 int userHandle) {
Jim Miller69aa4a92009-12-22 19:03:28 -0800747 try {
Dianne Hackborn2509d3c2010-03-08 12:54:25 -0800748 DevicePolicyManager dpm = getDevicePolicyManager();
Adrian Roosf80e66ce92015-01-15 23:27:24 +0100749 if (password == null || password.length() < MIN_LOCK_PASSWORD_SIZE) {
750 throw new IllegalArgumentException("password must not be null and at least "
751 + "of length " + MIN_LOCK_PASSWORD_SIZE);
Jim Miller31f90b62010-01-20 13:35:20 -0800752 }
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100753
Andres Morales8fa56652015-03-31 09:19:50 -0700754 getLockSettings().setLockPassword(password, savedPassword, userHandle);
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100755 int computedQuality = computePasswordQuality(password);
756
757 // Update the device encryption password.
758 if (userHandle == UserHandle.USER_OWNER
759 && LockPatternUtils.isDeviceEncryptionEnabled()) {
760 if (!isCredentialRequiredToDecrypt(true)) {
761 clearEncryptionPassword();
762 } else {
763 boolean numeric = computedQuality
764 == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC;
765 boolean numericComplex = computedQuality
766 == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX;
767 int type = numeric || numericComplex ? StorageManager.CRYPT_TYPE_PIN
768 : StorageManager.CRYPT_TYPE_PASSWORD;
769 updateEncryptionPassword(type, password);
770 }
771 }
772
773 setLong(PASSWORD_TYPE_KEY, Math.max(quality, computedQuality), userHandle);
774 if (computedQuality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
775 int letters = 0;
776 int uppercase = 0;
777 int lowercase = 0;
778 int numbers = 0;
779 int symbols = 0;
780 int nonletter = 0;
781 for (int i = 0; i < password.length(); i++) {
782 char c = password.charAt(i);
783 if (c >= 'A' && c <= 'Z') {
784 letters++;
785 uppercase++;
786 } else if (c >= 'a' && c <= 'z') {
787 letters++;
788 lowercase++;
789 } else if (c >= '0' && c <= '9') {
790 numbers++;
791 nonletter++;
792 } else {
793 symbols++;
794 nonletter++;
795 }
796 }
797 dpm.setActivePasswordState(Math.max(quality, computedQuality),
798 password.length(), letters, uppercase, lowercase,
799 numbers, symbols, nonletter, userHandle);
800 } else {
801 // The password is not anything.
802 dpm.setActivePasswordState(
803 DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED,
804 0, 0, 0, 0, 0, 0, 0, userHandle);
805 }
806
807 // Add the password to the password history. We assume all
808 // password hashes have the same length for simplicity of implementation.
809 String passwordHistory = getString(PASSWORD_HISTORY_KEY, userHandle);
810 if (passwordHistory == null) {
811 passwordHistory = "";
812 }
813 int passwordHistoryLength = getRequestedPasswordHistoryLength(userHandle);
814 if (passwordHistoryLength == 0) {
815 passwordHistory = "";
816 } else {
817 byte[] hash = passwordToHash(password, userHandle);
818 passwordHistory = new String(hash, StandardCharsets.UTF_8) + "," + passwordHistory;
819 // Cut it to contain passwordHistoryLength hashes
820 // and passwordHistoryLength -1 commas.
821 passwordHistory = passwordHistory.substring(0, Math.min(hash.length
822 * passwordHistoryLength + passwordHistoryLength - 1, passwordHistory
823 .length()));
824 }
825 setString(PASSWORD_HISTORY_KEY, passwordHistory, userHandle);
Adrian Roosf8f56bc2014-11-20 23:55:34 +0100826 onAfterChangingPassword(userHandle);
Amith Yamasani52c489c2012-03-28 11:42:42 -0700827 } catch (RemoteException re) {
Jim Miller69aa4a92009-12-22 19:03:28 -0800828 // Cant do much
Amith Yamasani52c489c2012-03-28 11:42:42 -0700829 Log.e(TAG, "Unable to save lock password " + re);
Jim Miller69aa4a92009-12-22 19:03:28 -0800830 }
831 }
832
Jim Millercd709882010-03-25 18:24:02 -0700833 /**
Svetoslav16e4a1a2014-09-29 18:16:20 -0700834 * Gets whether the device is encrypted.
835 *
836 * @return Whether the device is encrypted.
837 */
838 public static boolean isDeviceEncrypted() {
839 IMountService mountService = IMountService.Stub.asInterface(
840 ServiceManager.getService("mount"));
841 try {
842 return mountService.getEncryptionState() != IMountService.ENCRYPTION_STATE_NONE
843 && mountService.getPasswordType() != StorageManager.CRYPT_TYPE_DEFAULT;
844 } catch (RemoteException re) {
845 Log.e(TAG, "Error getting encryption state", re);
846 }
847 return true;
848 }
849
850 /**
Jim Miller6848dc82014-10-13 18:51:53 -0700851 * Determine if the device supports encryption, even if it's set to default. This
852 * differs from isDeviceEncrypted() in that it returns true even if the device is
853 * encrypted with the default password.
854 * @return true if device encryption is enabled
855 */
856 public static boolean isDeviceEncryptionEnabled() {
857 final String status = SystemProperties.get("ro.crypto.state", "unsupported");
858 return "encrypted".equalsIgnoreCase(status);
859 }
860
861 /**
Svetoslav16e4a1a2014-09-29 18:16:20 -0700862 * Clears the encryption password.
863 */
864 public void clearEncryptionPassword() {
865 updateEncryptionPassword(StorageManager.CRYPT_TYPE_DEFAULT, null);
866 }
867
868 /**
Jim Millercd709882010-03-25 18:24:02 -0700869 * Retrieves the quality mode we're in.
870 * {@see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)}
871 *
872 * @return stored password quality
873 */
874 public int getKeyguardStoredPasswordQuality() {
Adrian Roos1572ee32014-09-01 16:24:32 +0200875 return getKeyguardStoredPasswordQuality(getCurrentOrCallingUserId());
876 }
877
878 /**
879 * Retrieves the quality mode for {@param userHandle}.
880 * {@see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)}
881 *
882 * @return stored password quality
883 */
884 public int getKeyguardStoredPasswordQuality(int userHandle) {
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100885 return (int) getLong(PASSWORD_TYPE_KEY,
Adrian Roos1572ee32014-09-01 16:24:32 +0200886 DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, userHandle);
Jim Miller6edf2632011-09-05 16:03:14 -0700887 }
888
Danielle Millett58396982011-09-30 13:55:07 -0400889 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800890 * Deserialize a pattern.
891 * @param string The pattern serialized with {@link #patternToString}
892 * @return The pattern.
893 */
894 public static List<LockPatternView.Cell> stringToPattern(String string) {
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100895 if (string == null) {
896 return null;
897 }
898
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800899 List<LockPatternView.Cell> result = Lists.newArrayList();
900
901 final byte[] bytes = string.getBytes();
902 for (int i = 0; i < bytes.length; i++) {
903 byte b = bytes[i];
904 result.add(LockPatternView.Cell.of(b / 3, b % 3));
905 }
906 return result;
907 }
908
909 /**
910 * Serialize a pattern.
911 * @param pattern The pattern.
912 * @return The pattern in string form.
913 */
914 public static String patternToString(List<LockPatternView.Cell> pattern) {
915 if (pattern == null) {
916 return "";
917 }
918 final int patternSize = pattern.size();
919
920 byte[] res = new byte[patternSize];
921 for (int i = 0; i < patternSize; i++) {
922 LockPatternView.Cell cell = pattern.get(i);
923 res[i] = (byte) (cell.getRow() * 3 + cell.getColumn());
924 }
925 return new String(res);
926 }
Jim Miller69aa4a92009-12-22 19:03:28 -0800927
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800928 /*
929 * Generate an SHA-1 hash for the pattern. Not the most secure, but it is
930 * at least a second level of protection. First level is that the file
931 * is in a location only readable by the system process.
932 * @param pattern the gesture pattern.
933 * @return the hash of the pattern in a byte array.
934 */
Jim Millerde1af082013-09-11 14:58:26 -0700935 public static byte[] patternToHash(List<LockPatternView.Cell> pattern) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800936 if (pattern == null) {
937 return null;
938 }
Jim Miller69aa4a92009-12-22 19:03:28 -0800939
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800940 final int patternSize = pattern.size();
941 byte[] res = new byte[patternSize];
942 for (int i = 0; i < patternSize; i++) {
943 LockPatternView.Cell cell = pattern.get(i);
944 res[i] = (byte) (cell.getRow() * 3 + cell.getColumn());
945 }
946 try {
947 MessageDigest md = MessageDigest.getInstance("SHA-1");
948 byte[] hash = md.digest(res);
949 return hash;
950 } catch (NoSuchAlgorithmException nsa) {
951 return res;
952 }
953 }
954
Geoffrey Borggaard987672d22014-07-18 16:47:18 -0400955 private String getSalt(int userId) {
956 long salt = getLong(LOCK_PASSWORD_SALT_KEY, 0, userId);
Jim Miller11b019d2010-01-20 16:34:45 -0800957 if (salt == 0) {
958 try {
959 salt = SecureRandom.getInstance("SHA1PRNG").nextLong();
Geoffrey Borggaard987672d22014-07-18 16:47:18 -0400960 setLong(LOCK_PASSWORD_SALT_KEY, salt, userId);
961 Log.v(TAG, "Initialized lock password salt for user: " + userId);
Jim Miller11b019d2010-01-20 16:34:45 -0800962 } catch (NoSuchAlgorithmException e) {
963 // Throw an exception rather than storing a password we'll never be able to recover
964 throw new IllegalStateException("Couldn't get SecureRandom number", e);
965 }
966 }
967 return Long.toHexString(salt);
968 }
969
Jim Miller69aa4a92009-12-22 19:03:28 -0800970 /*
971 * Generate a hash for the given password. To avoid brute force attacks, we use a salted hash.
972 * Not the most secure, but it is at least a second level of protection. First level is that
973 * the file is in a location only readable by the system process.
Narayan Kamath78108a32014-12-16 12:56:23 +0000974 *
Jim Miller69aa4a92009-12-22 19:03:28 -0800975 * @param password the gesture pattern.
Narayan Kamath78108a32014-12-16 12:56:23 +0000976 *
Jim Miller69aa4a92009-12-22 19:03:28 -0800977 * @return the hash of the pattern in a byte array.
978 */
Geoffrey Borggaard987672d22014-07-18 16:47:18 -0400979 public byte[] passwordToHash(String password, int userId) {
Jim Miller69aa4a92009-12-22 19:03:28 -0800980 if (password == null) {
981 return null;
982 }
Narayan Kamath78108a32014-12-16 12:56:23 +0000983
Jim Miller69aa4a92009-12-22 19:03:28 -0800984 try {
Geoffrey Borggaard987672d22014-07-18 16:47:18 -0400985 byte[] saltedPassword = (password + getSalt(userId)).getBytes();
Narayan Kamath78108a32014-12-16 12:56:23 +0000986 byte[] sha1 = MessageDigest.getInstance("SHA-1").digest(saltedPassword);
987 byte[] md5 = MessageDigest.getInstance("MD5").digest(saltedPassword);
Jim Miller69aa4a92009-12-22 19:03:28 -0800988
Narayan Kamath78108a32014-12-16 12:56:23 +0000989 byte[] combined = new byte[sha1.length + md5.length];
990 System.arraycopy(sha1, 0, combined, 0, sha1.length);
991 System.arraycopy(md5, 0, combined, sha1.length, md5.length);
992
993 final char[] hexEncoded = HexEncoding.encode(combined);
994 return new String(hexEncoded).getBytes(StandardCharsets.UTF_8);
995 } catch (NoSuchAlgorithmException e) {
996 throw new AssertionError("Missing digest algorithm: ", e);
Jim Miller69aa4a92009-12-22 19:03:28 -0800997 }
Jim Miller69aa4a92009-12-22 19:03:28 -0800998 }
999
1000 /**
Adrian Roos9dd16eb2015-01-08 16:20:49 +01001001 * @return Whether the lock screen is secured.
1002 */
1003 public boolean isSecure() {
1004 return isSecure(getCurrentOrCallingUserId());
1005 }
1006
1007 /**
1008 * @param userId the user for which to report the value
1009 * @return Whether the lock screen is secured.
1010 */
1011 public boolean isSecure(int userId) {
1012 int mode = getKeyguardStoredPasswordQuality(userId);
1013 return isLockPatternEnabled(mode, userId) || isLockPasswordEnabled(mode, userId);
1014 }
1015
1016 /**
Adrian Roos230635e2015-01-07 20:50:29 +01001017 * @return Whether the lock password is enabled
Jim Miller69aa4a92009-12-22 19:03:28 -08001018 */
1019 public boolean isLockPasswordEnabled() {
Adrian Roosdce01222015-01-07 22:39:01 +01001020 return isLockPasswordEnabled(getCurrentOrCallingUserId());
1021 }
1022
Adrian Roosdce01222015-01-07 22:39:01 +01001023 public boolean isLockPasswordEnabled(int userId) {
Adrian Roos9dd16eb2015-01-08 16:20:49 +01001024 return isLockPasswordEnabled(getKeyguardStoredPasswordQuality(userId), userId);
1025 }
1026
1027 private boolean isLockPasswordEnabled(int mode, int userId) {
Danielle Millett73da5fe2011-09-13 16:20:05 -04001028 final boolean passwordEnabled = mode == DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC
1029 || mode == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC
Jim Miller85516d02014-01-31 17:08:37 -08001030 || mode == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX
Danielle Millett73da5fe2011-09-13 16:20:05 -04001031 || mode == DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC
1032 || mode == DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
Adrian Roos9dd16eb2015-01-08 16:20:49 +01001033 return passwordEnabled && savedPasswordExists(userId);
Jim Miller69aa4a92009-12-22 19:03:28 -08001034 }
1035
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001036 /**
Adrian Roos230635e2015-01-07 20:50:29 +01001037 * @return Whether the lock pattern is enabled
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001038 */
1039 public boolean isLockPatternEnabled() {
Adrian Roos50bfeec2014-11-20 16:21:11 +01001040 return isLockPatternEnabled(getCurrentOrCallingUserId());
1041 }
1042
Adrian Roos50bfeec2014-11-20 16:21:11 +01001043 public boolean isLockPatternEnabled(int userId) {
Adrian Roos9dd16eb2015-01-08 16:20:49 +01001044 return isLockPatternEnabled(getKeyguardStoredPasswordQuality(userId), userId);
Danielle Millett925a7d82012-03-19 18:02:20 -04001045 }
1046
Adrian Roos9dd16eb2015-01-08 16:20:49 +01001047 private boolean isLockPatternEnabled(int mode, int userId) {
1048 return mode == DevicePolicyManager.PASSWORD_QUALITY_SOMETHING
1049 && savedPatternExists(userId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001050 }
1051
1052 /**
1053 * @return Whether the visible pattern is enabled.
1054 */
1055 public boolean isVisiblePatternEnabled() {
Adrian Roosdce01222015-01-07 22:39:01 +01001056 return getBoolean(Settings.Secure.LOCK_PATTERN_VISIBLE, false, getCurrentOrCallingUserId());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001057 }
1058
1059 /**
1060 * Set whether the visible pattern is enabled.
1061 */
1062 public void setVisiblePatternEnabled(boolean enabled) {
Adrian Roosdce01222015-01-07 22:39:01 +01001063 int userId = getCurrentOrCallingUserId();
1064
1065 setBoolean(Settings.Secure.LOCK_PATTERN_VISIBLE, enabled, userId);
Paul Lawrence878ba0a2014-08-20 13:08:01 -07001066
1067 // Update for crypto if owner
Paul Lawrence878ba0a2014-08-20 13:08:01 -07001068 if (userId != UserHandle.USER_OWNER) {
1069 return;
1070 }
1071
1072 IBinder service = ServiceManager.getService("mount");
1073 if (service == null) {
1074 Log.e(TAG, "Could not find the mount service to update the user info");
1075 return;
1076 }
1077
1078 IMountService mountService = IMountService.Stub.asInterface(service);
1079 try {
Elliott Hughesf839b4f2014-09-26 12:30:47 -07001080 mountService.setField(StorageManager.PATTERN_VISIBLE_KEY, enabled ? "1" : "0");
Paul Lawrence878ba0a2014-08-20 13:08:01 -07001081 } catch (RemoteException e) {
1082 Log.e(TAG, "Error changing pattern visible state", e);
1083 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001084 }
1085
1086 /**
1087 * @return Whether tactile feedback for the pattern is enabled.
1088 */
1089 public boolean isTactileFeedbackEnabled() {
Jeff Sharkey5ed9d682012-10-10 14:28:27 -07001090 return Settings.System.getIntForUser(mContentResolver,
1091 Settings.System.HAPTIC_FEEDBACK_ENABLED, 1, UserHandle.USER_CURRENT) != 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001092 }
1093
1094 /**
1095 * Set and store the lockout deadline, meaning the user can't attempt his/her unlock
1096 * pattern until the deadline has passed.
1097 * @return the chosen deadline.
1098 */
1099 public long setLockoutAttemptDeadline() {
1100 final long deadline = SystemClock.elapsedRealtime() + FAILED_ATTEMPT_TIMEOUT_MS;
Adrian Roosdce01222015-01-07 22:39:01 +01001101 setLong(LOCKOUT_ATTEMPT_DEADLINE, deadline, getCurrentOrCallingUserId());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001102 return deadline;
1103 }
1104
1105 /**
1106 * @return The elapsed time in millis in the future when the user is allowed to
1107 * attempt to enter his/her lock pattern, or 0 if the user is welcome to
1108 * enter a pattern.
1109 */
1110 public long getLockoutAttemptDeadline() {
Adrian Roosdce01222015-01-07 22:39:01 +01001111 final long deadline = getLong(LOCKOUT_ATTEMPT_DEADLINE, 0L, getCurrentOrCallingUserId());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001112 final long now = SystemClock.elapsedRealtime();
1113 if (deadline < now || deadline > (now + FAILED_ATTEMPT_TIMEOUT_MS)) {
1114 return 0L;
1115 }
1116 return deadline;
1117 }
1118
Jim Millerf45bb402013-08-20 18:58:32 -07001119 private boolean getBoolean(String secureSettingKey, boolean defaultValue, int userId) {
Amith Yamasani52c489c2012-03-28 11:42:42 -07001120 try {
Jim Millerf45bb402013-08-20 18:58:32 -07001121 return getLockSettings().getBoolean(secureSettingKey, defaultValue, userId);
Amith Yamasani52c489c2012-03-28 11:42:42 -07001122 } catch (RemoteException re) {
1123 return defaultValue;
1124 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001125 }
1126
Jim Millerf45bb402013-08-20 18:58:32 -07001127 private void setBoolean(String secureSettingKey, boolean enabled, int userId) {
Amith Yamasani52c489c2012-03-28 11:42:42 -07001128 try {
Jim Millerf45bb402013-08-20 18:58:32 -07001129 getLockSettings().setBoolean(secureSettingKey, enabled, userId);
Amith Yamasani52c489c2012-03-28 11:42:42 -07001130 } catch (RemoteException re) {
1131 // What can we do?
1132 Log.e(TAG, "Couldn't write boolean " + secureSettingKey + re);
1133 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001134 }
1135
Geoffrey Borggaard987672d22014-07-18 16:47:18 -04001136 private long getLong(String secureSettingKey, long defaultValue, int userHandle) {
1137 try {
1138 return getLockSettings().getLong(secureSettingKey, defaultValue, userHandle);
1139 } catch (RemoteException re) {
1140 return defaultValue;
1141 }
1142 }
1143
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001144 private void setLong(String secureSettingKey, long value, int userHandle) {
Amith Yamasani52c489c2012-03-28 11:42:42 -07001145 try {
Kenny Guy0cf13702013-11-29 16:33:05 +00001146 getLockSettings().setLong(secureSettingKey, value, userHandle);
Amith Yamasani52c489c2012-03-28 11:42:42 -07001147 } catch (RemoteException re) {
1148 // What can we do?
1149 Log.e(TAG, "Couldn't write long " + secureSettingKey + re);
1150 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001151 }
1152
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001153 private String getString(String secureSettingKey, int userHandle) {
Amith Yamasani52c489c2012-03-28 11:42:42 -07001154 try {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001155 return getLockSettings().getString(secureSettingKey, null, userHandle);
Amith Yamasani52c489c2012-03-28 11:42:42 -07001156 } catch (RemoteException re) {
1157 return null;
1158 }
Konstantin Lopyrev863f22d2010-05-12 17:16:58 -07001159 }
1160
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001161 private void setString(String secureSettingKey, String value, int userHandle) {
Amith Yamasani52c489c2012-03-28 11:42:42 -07001162 try {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001163 getLockSettings().setString(secureSettingKey, value, userHandle);
Amith Yamasani52c489c2012-03-28 11:42:42 -07001164 } catch (RemoteException re) {
1165 // What can we do?
1166 Log.e(TAG, "Couldn't write string " + secureSettingKey + re);
1167 }
Konstantin Lopyrev863f22d2010-05-12 17:16:58 -07001168 }
1169
Jim Millera4edd152012-01-06 18:24:04 -08001170 public void setPowerButtonInstantlyLocks(boolean enabled) {
Adrian Roosdce01222015-01-07 22:39:01 +01001171 setBoolean(LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS, enabled, getCurrentOrCallingUserId());
Jim Millera4edd152012-01-06 18:24:04 -08001172 }
1173
1174 public boolean getPowerButtonInstantlyLocks() {
Adrian Roosdce01222015-01-07 22:39:01 +01001175 return getBoolean(LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS, true,
1176 getCurrentOrCallingUserId());
Jim Millera4edd152012-01-06 18:24:04 -08001177 }
Jim Millera9768602012-11-06 22:17:25 -08001178
Adrian Roos82142c22014-03-27 14:56:59 +01001179 public void setEnabledTrustAgents(Collection<ComponentName> activeTrustAgents) {
1180 setEnabledTrustAgents(activeTrustAgents, getCurrentOrCallingUserId());
1181 }
1182
1183 public List<ComponentName> getEnabledTrustAgents() {
1184 return getEnabledTrustAgents(getCurrentOrCallingUserId());
1185 }
1186
1187 public void setEnabledTrustAgents(Collection<ComponentName> activeTrustAgents, int userId) {
1188 StringBuilder sb = new StringBuilder();
1189 for (ComponentName cn : activeTrustAgents) {
1190 if (sb.length() > 0) {
1191 sb.append(',');
1192 }
1193 sb.append(cn.flattenToShortString());
1194 }
1195 setString(ENABLED_TRUST_AGENTS, sb.toString(), userId);
1196 getTrustManager().reportEnabledTrustAgentsChanged(getCurrentOrCallingUserId());
1197 }
1198
1199 public List<ComponentName> getEnabledTrustAgents(int userId) {
1200 String serialized = getString(ENABLED_TRUST_AGENTS, userId);
1201 if (TextUtils.isEmpty(serialized)) {
1202 return null;
1203 }
1204 String[] split = serialized.split(",");
1205 ArrayList<ComponentName> activeTrustAgents = new ArrayList<ComponentName>(split.length);
1206 for (String s : split) {
1207 if (!TextUtils.isEmpty(s)) {
1208 activeTrustAgents.add(ComponentName.unflattenFromString(s));
1209 }
1210 }
1211 return activeTrustAgents;
1212 }
Adrian Roos2c12cfa2014-06-25 23:28:53 +02001213
1214 /**
1215 * @see android.app.trust.TrustManager#reportRequireCredentialEntry(int)
1216 */
1217 public void requireCredentialEntry(int userId) {
1218 getTrustManager().reportRequireCredentialEntry(userId);
1219 }
Adrian Roos4b9e3242014-08-20 23:36:25 +02001220
Adrian Roosf8f56bc2014-11-20 23:55:34 +01001221 private void onAfterChangingPassword(int userHandle) {
1222 getTrustManager().reportEnabledTrustAgentsChanged(userHandle);
Adrian Roos4b9e3242014-08-20 23:36:25 +02001223 }
Jim Millerdd5de712014-10-16 19:50:18 -07001224
1225 public boolean isCredentialRequiredToDecrypt(boolean defaultValue) {
1226 final int value = Settings.Global.getInt(mContentResolver,
1227 Settings.Global.REQUIRE_PASSWORD_TO_DECRYPT, -1);
1228 return value == -1 ? defaultValue : (value != 0);
1229 }
1230
1231 public void setCredentialRequiredToDecrypt(boolean required) {
1232 if (getCurrentUser() != UserHandle.USER_OWNER) {
1233 Log.w(TAG, "Only device owner may call setCredentialRequiredForDecrypt()");
1234 return;
1235 }
1236 Settings.Global.putInt(mContext.getContentResolver(),
1237 Settings.Global.REQUIRE_PASSWORD_TO_DECRYPT, required ? 1 : 0);
1238 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001239}