blob: 795012dab4d13cbf14855492391f869d09f97004 [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
Adrian Roosb5e47222015-08-14 15:53:06 -070019import android.annotation.IntDef;
Dianne Hackborn87bba1e2010-02-26 17:25:54 -080020import android.app.admin.DevicePolicyManager;
Adrian Roosb5e47222015-08-14 15:53:06 -070021import android.app.trust.IStrongAuthTracker;
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;
Clara Bayarria1771112015-12-18 16:29:18 +000026import android.content.pm.UserInfo;
Paul Lawrence3a5a0be2014-09-25 09:26:34 -070027import android.os.AsyncTask;
Adrian Roosb5e47222015-08-14 15:53:06 -070028import android.os.Handler;
Jason parksf7b3cd42011-01-27 09:28:25 -060029import android.os.IBinder;
Xiyuan Xiaaa262942015-05-05 15:18:45 -070030import android.os.Looper;
Adrian Roosb5e47222015-08-14 15:53:06 -070031import android.os.Message;
Jim Miller69ac9882010-02-24 15:35:05 -080032import android.os.RemoteException;
33import android.os.ServiceManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080034import android.os.SystemClock;
Jim Miller6848dc82014-10-13 18:51:53 -070035import android.os.SystemProperties;
Dianne Hackbornf02b60a2012-08-16 10:48:27 -070036import android.os.UserHandle;
Clara Bayarria1771112015-12-18 16:29:18 +000037import android.os.UserManager;
Jason parksf7b3cd42011-01-27 09:28:25 -060038import android.os.storage.IMountService;
Paul Lawrence8e397362014-01-27 15:22:30 -080039import android.os.storage.StorageManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080040import android.provider.Settings;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080041import android.text.TextUtils;
42import android.util.Log;
Adrian Roosb5e47222015-08-14 15:53:06 -070043import android.util.SparseIntArray;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080044
Michael Jurka1254f2f2012-10-25 11:44:31 -070045import com.google.android.collect.Lists;
Adrian Roos9dd16eb2015-01-08 16:20:49 +010046
Adrian Roosb5e47222015-08-14 15:53:06 -070047import java.lang.annotation.Retention;
48import java.lang.annotation.RetentionPolicy;
Narayan Kamath78108a32014-12-16 12:56:23 +000049import java.nio.charset.StandardCharsets;
Brian Carlstrom929a1c22011-02-01 21:54:09 -080050import java.security.MessageDigest;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080051import java.security.NoSuchAlgorithmException;
Jim Miller11b019d2010-01-20 16:34:45 -080052import java.security.SecureRandom;
Adrian Roos82142c22014-03-27 14:56:59 +010053import java.util.ArrayList;
54import java.util.Collection;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080055import java.util.List;
56
Adrian Roosc2e01682015-01-15 23:20:20 +010057import libcore.util.HexEncoding;
58
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080059/**
Brian Carlstrom5cfee3f2011-05-31 01:00:15 -070060 * Utilities for the lock pattern and its settings.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080061 */
62public class LockPatternUtils {
63
64 private static final String TAG = "LockPatternUtils";
Brian Colonnaa0ee0042014-07-16 13:50:47 -040065 private static final boolean DEBUG = false;
Jim Miller69aa4a92009-12-22 19:03:28 -080066
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080067 /**
Bryce Lee46145962015-12-14 14:39:10 -080068 * The key to identify when the lock pattern enabled flag is being acccessed for legacy reasons.
69 */
70 public static final String LEGACY_LOCK_PATTERN_ENABLED = "legacy_lock_pattern_enabled";
71
72 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080073 * The number of incorrect attempts before which we fall back on an alternative
74 * method of verifying the user, and resetting their lock pattern.
75 */
76 public static final int FAILED_ATTEMPTS_BEFORE_RESET = 20;
77
78 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080079 * The interval of the countdown for showing progress of the lockout.
80 */
81 public static final long FAILED_ATTEMPT_COUNTDOWN_INTERVAL_MS = 1000L;
82
Jim Miller4f369952011-08-19 18:29:22 -070083
84 /**
85 * This dictates when we start telling the user that continued failed attempts will wipe
86 * their device.
87 */
88 public static final int FAILED_ATTEMPTS_BEFORE_WIPE_GRACE = 5;
89
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080090 /**
91 * The minimum number of dots in a valid pattern.
92 */
93 public static final int MIN_LOCK_PATTERN_SIZE = 4;
94
95 /**
Adrian Roosf80e66ce92015-01-15 23:27:24 +010096 * The minimum size of a valid password.
97 */
98 public static final int MIN_LOCK_PASSWORD_SIZE = 4;
99
100 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800101 * The minimum number of dots the user must include in a wrong pattern
102 * attempt for it to be counted against the counts that affect
103 * {@link #FAILED_ATTEMPTS_BEFORE_TIMEOUT} and {@link #FAILED_ATTEMPTS_BEFORE_RESET}
104 */
Jim Miller4f369952011-08-19 18:29:22 -0700105 public static final int MIN_PATTERN_REGISTER_FAIL = MIN_LOCK_PATTERN_SIZE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800106
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100107 @Deprecated
Jeff Sharkey7a96c392012-11-15 14:01:46 -0800108 public final static String LOCKOUT_PERMANENT_KEY = "lockscreen.lockedoutpermanently";
109 public final static String LOCKOUT_ATTEMPT_DEADLINE = "lockscreen.lockoutattemptdeadline";
Andres Morales23974272015-05-14 22:42:26 -0700110 public final static String LOCKOUT_ATTEMPT_TIMEOUT_MS = "lockscreen.lockoutattempttimeoutmss";
Jeff Sharkey7a96c392012-11-15 14:01:46 -0800111 public final static String PATTERN_EVER_CHOSEN_KEY = "lockscreen.patterneverchosen";
Jim Miller69aa4a92009-12-22 19:03:28 -0800112 public final static String PASSWORD_TYPE_KEY = "lockscreen.password_type";
Adrian Roos230635e2015-01-07 20:50:29 +0100113 @Deprecated
114 public final static String PASSWORD_TYPE_ALTERNATE_KEY = "lockscreen.password_type_alternate";
Jeff Sharkey7a96c392012-11-15 14:01:46 -0800115 public final static String LOCK_PASSWORD_SALT_KEY = "lockscreen.password_salt";
116 public final static String DISABLE_LOCKSCREEN_KEY = "lockscreen.disabled";
117 public final static String LOCKSCREEN_OPTIONS = "lockscreen.options";
Adrian Roos230635e2015-01-07 20:50:29 +0100118 @Deprecated
Jim Miller6edf2632011-09-05 16:03:14 -0700119 public final static String LOCKSCREEN_BIOMETRIC_WEAK_FALLBACK
120 = "lockscreen.biometric_weak_fallback";
Adrian Roos230635e2015-01-07 20:50:29 +0100121 @Deprecated
Danielle Millett7a072192011-10-03 17:36:01 -0400122 public final static String BIOMETRIC_WEAK_EVER_CHOSEN_KEY
123 = "lockscreen.biometricweakeverchosen";
Jim Millera4edd152012-01-06 18:24:04 -0800124 public final static String LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS
125 = "lockscreen.power_button_instantly_locks";
Adrian Roos230635e2015-01-07 20:50:29 +0100126 @Deprecated
Jim Millerf45bb402013-08-20 18:58:32 -0700127 public final static String LOCKSCREEN_WIDGETS_ENABLED = "lockscreen.widgets_enabled";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800128
Jeff Sharkey7a96c392012-11-15 14:01:46 -0800129 public final static String PASSWORD_HISTORY_KEY = "lockscreen.passwordhistory";
Konstantin Lopyrev863f22d2010-05-12 17:16:58 -0700130
Jim Miller187ec582013-04-15 18:27:54 -0700131 private static final String LOCK_SCREEN_OWNER_INFO = Settings.Secure.LOCK_SCREEN_OWNER_INFO;
132 private static final String LOCK_SCREEN_OWNER_INFO_ENABLED =
133 Settings.Secure.LOCK_SCREEN_OWNER_INFO_ENABLED;
134
Andrei Stingaceanu6644cd92015-11-10 13:03:31 +0000135 private static final String LOCK_SCREEN_DEVICE_OWNER_INFO = "lockscreen.device_owner_info";
136
Adrian Roos82142c22014-03-27 14:56:59 +0100137 private static final String ENABLED_TRUST_AGENTS = "lockscreen.enabledtrustagents";
Adrian Roosc13723f2016-01-12 20:29:03 +0100138 private static final String IS_TRUST_USUALLY_MANAGED = "lockscreen.istrustusuallymanaged";
Adrian Roos82142c22014-03-27 14:56:59 +0100139
Clara Bayarria1771112015-12-18 16:29:18 +0000140 private static final String SEPARATE_PROFILE_CHALLENGE_KEY = "lockscreen.profilechallenge";
141
Jim Miller85516d02014-01-31 17:08:37 -0800142 // Maximum allowed number of repeated or ordered characters in a sequence before we'll
143 // consider it a complex PIN/password.
144 public static final int MAX_ALLOWED_SEQUENCE = 3;
145
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800146 private final Context mContext;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800147 private final ContentResolver mContentResolver;
Jim Miller31f90b62010-01-20 13:35:20 -0800148 private DevicePolicyManager mDevicePolicyManager;
Amith Yamasani52c489c2012-03-28 11:42:42 -0700149 private ILockSettings mLockSettingsService;
Clara Bayarria1771112015-12-18 16:29:18 +0000150 private UserManager mUserManager;
Jim Milleree82f8f2012-10-01 16:26:18 -0700151
Adrian Roosc13723f2016-01-12 20:29:03 +0100152 /**
153 * Use {@link TrustManager#isTrustUsuallyManaged(int)}.
154 *
155 * This returns the lazily-peristed value and should only be used by TrustManagerService.
156 */
157 public boolean isTrustUsuallyManaged(int userId) {
158 if (!(mLockSettingsService instanceof ILockSettings.Stub)) {
159 throw new IllegalStateException("May only be called by TrustManagerService. "
160 + "Use TrustManager.isTrustUsuallyManaged()");
161 }
162 try {
163 return getLockSettings().getBoolean(IS_TRUST_USUALLY_MANAGED, false, userId);
164 } catch (RemoteException e) {
165 return false;
166 }
167 }
168
169 public void setTrustUsuallyManaged(boolean managed, int userId) {
170 try {
171 getLockSettings().setBoolean(IS_TRUST_USUALLY_MANAGED, managed, userId);
172 } catch (RemoteException e) {
173 // System dead.
174 }
175 }
Andres Morales23974272015-05-14 22:42:26 -0700176
177 public static final class RequestThrottledException extends Exception {
178 private int mTimeoutMs;
179 public RequestThrottledException(int timeoutMs) {
180 mTimeoutMs = timeoutMs;
181 }
182
183 /**
184 * @return The amount of time in ms before another request may
185 * be executed
186 */
187 public int getTimeoutMs() {
188 return mTimeoutMs;
189 }
190
191 }
192
Jim Millercd709882010-03-25 18:24:02 -0700193 public DevicePolicyManager getDevicePolicyManager() {
Jim Miller5b0fb3a2010-02-23 13:46:35 -0800194 if (mDevicePolicyManager == null) {
195 mDevicePolicyManager =
196 (DevicePolicyManager)mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
197 if (mDevicePolicyManager == null) {
198 Log.e(TAG, "Can't get DevicePolicyManagerService: is it running?",
199 new IllegalStateException("Stack trace:"));
200 }
201 }
202 return mDevicePolicyManager;
203 }
Amith Yamasani52c489c2012-03-28 11:42:42 -0700204
Clara Bayarria1771112015-12-18 16:29:18 +0000205 private UserManager getUserManager() {
206 if (mUserManager == null) {
207 mUserManager = UserManager.get(mContext);
208 }
209 return mUserManager;
210 }
211
Adrian Roos82142c22014-03-27 14:56:59 +0100212 private TrustManager getTrustManager() {
213 TrustManager trust = (TrustManager) mContext.getSystemService(Context.TRUST_SERVICE);
214 if (trust == null) {
215 Log.e(TAG, "Can't get TrustManagerService: is it running?",
216 new IllegalStateException("Stack trace:"));
217 }
218 return trust;
219 }
220
Jim Miller31f90b62010-01-20 13:35:20 -0800221 public LockPatternUtils(Context context) {
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800222 mContext = context;
Jim Miller31f90b62010-01-20 13:35:20 -0800223 mContentResolver = context.getContentResolver();
Amith Yamasani52c489c2012-03-28 11:42:42 -0700224 }
Jim Miller69aa4a92009-12-22 19:03:28 -0800225
Amith Yamasani52c489c2012-03-28 11:42:42 -0700226 private ILockSettings getLockSettings() {
227 if (mLockSettingsService == null) {
Adrian Roos450ce9f2014-10-29 14:30:37 +0100228 ILockSettings service = ILockSettings.Stub.asInterface(
229 ServiceManager.getService("lock_settings"));
Adrian Roos138b8332014-11-11 13:51:07 +0100230 mLockSettingsService = service;
Brad Fitzpatrick90881002010-08-23 18:30:08 -0700231 }
Amith Yamasani52c489c2012-03-28 11:42:42 -0700232 return mLockSettingsService;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800233 }
234
Adrian Roos8150d2a2015-04-16 17:11:20 -0700235 public int getRequestedMinimumPasswordLength(int userId) {
236 return getDevicePolicyManager().getPasswordMinimumLength(null, userId);
Jim Miller31f90b62010-01-20 13:35:20 -0800237 }
238
Jim Miller31f90b62010-01-20 13:35:20 -0800239 /**
240 * Gets the device policy password mode. If the mode is non-specific, returns
241 * MODE_PATTERN which allows the user to choose anything.
Jim Miller31f90b62010-01-20 13:35:20 -0800242 */
Adrian Roos8150d2a2015-04-16 17:11:20 -0700243 public int getRequestedPasswordQuality(int userId) {
244 return getDevicePolicyManager().getPasswordQuality(null, userId);
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100245 }
246
247 private int getRequestedPasswordHistoryLength(int userId) {
248 return getDevicePolicyManager().getPasswordHistoryLength(null, userId);
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700249 }
250
Adrian Roos8150d2a2015-04-16 17:11:20 -0700251 public int getRequestedPasswordMinimumLetters(int userId) {
252 return getDevicePolicyManager().getPasswordMinimumLetters(null, userId);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700253 }
254
Adrian Roos8150d2a2015-04-16 17:11:20 -0700255 public int getRequestedPasswordMinimumUpperCase(int userId) {
256 return getDevicePolicyManager().getPasswordMinimumUpperCase(null, userId);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700257 }
258
Adrian Roos8150d2a2015-04-16 17:11:20 -0700259 public int getRequestedPasswordMinimumLowerCase(int userId) {
260 return getDevicePolicyManager().getPasswordMinimumLowerCase(null, userId);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700261 }
262
Adrian Roos8150d2a2015-04-16 17:11:20 -0700263 public int getRequestedPasswordMinimumNumeric(int userId) {
264 return getDevicePolicyManager().getPasswordMinimumNumeric(null, userId);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700265 }
266
Adrian Roos8150d2a2015-04-16 17:11:20 -0700267 public int getRequestedPasswordMinimumSymbols(int userId) {
268 return getDevicePolicyManager().getPasswordMinimumSymbols(null, userId);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700269 }
270
Adrian Roos8150d2a2015-04-16 17:11:20 -0700271 public int getRequestedPasswordMinimumNonLetter(int userId) {
272 return getDevicePolicyManager().getPasswordMinimumNonLetter(null, userId);
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700273 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700274
Adrian Roos8150d2a2015-04-16 17:11:20 -0700275 public void reportFailedPasswordAttempt(int userId) {
Adrian Roos4f994eb2014-07-23 15:45:05 +0200276 getDevicePolicyManager().reportFailedPasswordAttempt(userId);
277 getTrustManager().reportUnlockAttempt(false /* authenticated */, userId);
Adrian Roosaf4ab3e2015-09-02 13:23:30 -0700278 requireStrongAuth(StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_WRONG_CREDENTIAL, userId);
Jim Miller31f90b62010-01-20 13:35:20 -0800279 }
280
Adrian Roos8150d2a2015-04-16 17:11:20 -0700281 public void reportSuccessfulPasswordAttempt(int userId) {
282 getDevicePolicyManager().reportSuccessfulPasswordAttempt(userId);
283 getTrustManager().reportUnlockAttempt(true /* authenticated */, userId);
Jim Miller31f90b62010-01-20 13:35:20 -0800284 }
285
Clara Bayarri51e41ad2016-02-11 17:48:53 +0000286 public int getCurrentFailedPasswordAttempts(int userId) {
287 return getDevicePolicyManager().getCurrentFailedPasswordAttempts(userId);
288 }
289
290 public int getMaximumFailedPasswordsForWipe(int userId) {
291 return getDevicePolicyManager().getMaximumFailedPasswordsForWipe(
292 null /* componentName */, userId);
293 }
294
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800295 /**
Andres Moralesd9fc85a2015-04-09 19:14:42 -0700296 * Check to see if a pattern matches the saved pattern.
297 * If pattern matches, return an opaque attestation that the challenge
298 * was verified.
299 *
300 * @param pattern The pattern to check.
301 * @param challenge The challenge to verify against the pattern
302 * @return the attestation that the challenge was verified, or null.
303 */
Andres Morales23974272015-05-14 22:42:26 -0700304 public byte[] verifyPattern(List<LockPatternView.Cell> pattern, long challenge, int userId)
305 throws RequestThrottledException {
Xiyuan Xiaaa262942015-05-05 15:18:45 -0700306 throwIfCalledOnMainThread();
Andres Moralesd9fc85a2015-04-09 19:14:42 -0700307 try {
Andres Morales23974272015-05-14 22:42:26 -0700308 VerifyCredentialResponse response =
309 getLockSettings().verifyPattern(patternToString(pattern), challenge, userId);
310 if (response == null) {
311 // Shouldn't happen
312 return null;
313 }
314
315 if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
316 return response.getPayload();
317 } else if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_RETRY) {
318 throw new RequestThrottledException(response.getTimeout());
319 } else {
320 return null;
321 }
Andres Moralesd9fc85a2015-04-09 19:14:42 -0700322 } catch (RemoteException re) {
323 return null;
324 }
325 }
326
327 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800328 * Check to see if a pattern matches the saved pattern. If no pattern exists,
329 * always returns true.
330 * @param pattern The pattern to check.
Jim Miller69aa4a92009-12-22 19:03:28 -0800331 * @return Whether the pattern matches the stored one.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800332 */
Andres Morales23974272015-05-14 22:42:26 -0700333 public boolean checkPattern(List<LockPatternView.Cell> pattern, int userId)
334 throws RequestThrottledException {
Xiyuan Xiaaa262942015-05-05 15:18:45 -0700335 throwIfCalledOnMainThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800336 try {
Andres Morales23974272015-05-14 22:42:26 -0700337 VerifyCredentialResponse response =
338 getLockSettings().checkPattern(patternToString(pattern), userId);
339
340 if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
341 return true;
342 } else if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_RETRY) {
343 throw new RequestThrottledException(response.getTimeout());
344 } else {
345 return false;
346 }
Amith Yamasani52c489c2012-03-28 11:42:42 -0700347 } catch (RemoteException re) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800348 return true;
349 }
350 }
351
352 /**
Andres Moralesd9fc85a2015-04-09 19:14:42 -0700353 * Check to see if a password matches the saved password.
354 * If password matches, return an opaque attestation that the challenge
355 * was verified.
356 *
357 * @param password The password to check.
358 * @param challenge The challenge to verify against the password
359 * @return the attestation that the challenge was verified, or null.
360 */
Andres Morales23974272015-05-14 22:42:26 -0700361 public byte[] verifyPassword(String password, long challenge, int userId)
362 throws RequestThrottledException {
Xiyuan Xiaaa262942015-05-05 15:18:45 -0700363 throwIfCalledOnMainThread();
Andres Moralesd9fc85a2015-04-09 19:14:42 -0700364 try {
Andres Morales23974272015-05-14 22:42:26 -0700365 VerifyCredentialResponse response =
366 getLockSettings().verifyPassword(password, challenge, userId);
367
368 if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
369 return response.getPayload();
370 } else if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_RETRY) {
371 throw new RequestThrottledException(response.getTimeout());
372 } else {
373 return null;
374 }
Andres Moralesd9fc85a2015-04-09 19:14:42 -0700375 } catch (RemoteException re) {
376 return null;
377 }
378 }
379
380 /**
Jim Miller69aa4a92009-12-22 19:03:28 -0800381 * Check to see if a password matches the saved password. If no password exists,
382 * always returns true.
383 * @param password The password to check.
384 * @return Whether the password matches the stored one.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800385 */
Andres Morales23974272015-05-14 22:42:26 -0700386 public boolean checkPassword(String password, int userId) throws RequestThrottledException {
Xiyuan Xiaaa262942015-05-05 15:18:45 -0700387 throwIfCalledOnMainThread();
Jim Miller69aa4a92009-12-22 19:03:28 -0800388 try {
Andres Morales23974272015-05-14 22:42:26 -0700389 VerifyCredentialResponse response =
390 getLockSettings().checkPassword(password, userId);
391 if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
392 return true;
393 } else if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_RETRY) {
394 throw new RequestThrottledException(response.getTimeout());
395 } else {
396 return false;
397 }
Amith Yamasani52c489c2012-03-28 11:42:42 -0700398 } catch (RemoteException re) {
Jim Miller69aa4a92009-12-22 19:03:28 -0800399 return true;
400 }
401 }
402
403 /**
Paul Lawrence945490c2014-03-27 16:37:28 +0000404 * Check to see if vold already has the password.
405 * Note that this also clears vold's copy of the password.
406 * @return Whether the vold password matches or not.
407 */
Adrian Roos8150d2a2015-04-16 17:11:20 -0700408 public boolean checkVoldPassword(int userId) {
Paul Lawrence945490c2014-03-27 16:37:28 +0000409 try {
410 return getLockSettings().checkVoldPassword(userId);
411 } catch (RemoteException re) {
412 return false;
413 }
414 }
415
416 /**
Konstantin Lopyrev863f22d2010-05-12 17:16:58 -0700417 * Check to see if a password matches any of the passwords stored in the
418 * password history.
419 *
420 * @param password The password to check.
421 * @return Whether the password matches any in the history.
422 */
Adrian Roos8150d2a2015-04-16 17:11:20 -0700423 public boolean checkPasswordHistory(String password, int userId) {
Geoffrey Borggaard987672d22014-07-18 16:47:18 -0400424 String passwordHashString = new String(
Adrian Roosdce01222015-01-07 22:39:01 +0100425 passwordToHash(password, userId), StandardCharsets.UTF_8);
426 String passwordHistory = getString(PASSWORD_HISTORY_KEY, userId);
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700427 if (passwordHistory == null) {
428 return false;
429 }
430 // Password History may be too long...
431 int passwordHashLength = passwordHashString.length();
Adrian Roos8150d2a2015-04-16 17:11:20 -0700432 int passwordHistoryLength = getRequestedPasswordHistoryLength(userId);
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700433 if(passwordHistoryLength == 0) {
434 return false;
435 }
436 int neededPasswordHistoryLength = passwordHashLength * passwordHistoryLength
437 + passwordHistoryLength - 1;
438 if (passwordHistory.length() > neededPasswordHistoryLength) {
439 passwordHistory = passwordHistory.substring(0, neededPasswordHistoryLength);
440 }
441 return passwordHistory.contains(passwordHashString);
Konstantin Lopyrev863f22d2010-05-12 17:16:58 -0700442 }
443
444 /**
Jim Miller69aa4a92009-12-22 19:03:28 -0800445 * Check to see if the user has stored a lock pattern.
446 * @return Whether a saved pattern exists.
447 */
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100448 private boolean savedPatternExists(int userId) {
Amith Yamasani52c489c2012-03-28 11:42:42 -0700449 try {
Adrian Roos50bfeec2014-11-20 16:21:11 +0100450 return getLockSettings().havePattern(userId);
Amith Yamasani52c489c2012-03-28 11:42:42 -0700451 } catch (RemoteException re) {
452 return false;
453 }
Jim Miller69aa4a92009-12-22 19:03:28 -0800454 }
455
456 /**
457 * Check to see if the user has stored a lock pattern.
458 * @return Whether a saved pattern exists.
459 */
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100460 private boolean savedPasswordExists(int userId) {
Amith Yamasani52c489c2012-03-28 11:42:42 -0700461 try {
Adrian Roos50bfeec2014-11-20 16:21:11 +0100462 return getLockSettings().havePassword(userId);
Amith Yamasani52c489c2012-03-28 11:42:42 -0700463 } catch (RemoteException re) {
464 return false;
465 }
Jim Miller69aa4a92009-12-22 19:03:28 -0800466 }
467
468 /**
The Android Open Source Projectba87e3e2009-03-13 13:04:22 -0700469 * Return true if the user has ever chosen a pattern. This is true even if the pattern is
470 * currently cleared.
471 *
472 * @return True if the user has ever chosen a pattern.
473 */
Adrian Roos8150d2a2015-04-16 17:11:20 -0700474 public boolean isPatternEverChosen(int userId) {
475 return getBoolean(PATTERN_EVER_CHOSEN_KEY, false, userId);
Adrian Roosdce01222015-01-07 22:39:01 +0100476 }
477
478 /**
479 * Used by device policy manager to validate the current password
480 * information it has.
481 */
482 public int getActivePasswordQuality(int userId) {
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100483 int quality = getKeyguardStoredPasswordQuality(userId);
Adrian Roosdce01222015-01-07 22:39:01 +0100484
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100485 if (isLockPasswordEnabled(quality, userId)) {
486 // Quality is a password and a password exists. Return the quality.
487 return quality;
488 }
489
490 if (isLockPatternEnabled(quality, userId)) {
491 // Quality is a pattern and a pattern exists. Return the quality.
492 return quality;
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700493 }
Danielle Millettc8fb5322011-10-04 12:18:51 -0400494
Adrian Roosdce01222015-01-07 22:39:01 +0100495 return DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700496 }
Jim Millercd709882010-03-25 18:24:02 -0700497
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700498 /**
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800499 * Clear any lock pattern or password.
500 */
Adrian Roos230635e2015-01-07 20:50:29 +0100501 public void clearLock(int userHandle) {
Adrian Roosf8f56bc2014-11-20 23:55:34 +0100502 setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, userHandle);
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100503
504 try {
Andres Morales8fa56652015-03-31 09:19:50 -0700505 getLockSettings().setLockPassword(null, null, userHandle);
506 getLockSettings().setLockPattern(null, null, userHandle);
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100507 } catch (RemoteException e) {
508 // well, we tried...
509 }
510
Xiaohui Chen86c69dd2015-08-27 15:44:02 -0700511 if (userHandle == UserHandle.USER_SYSTEM) {
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100512 // Set the encryption password to default.
513 updateEncryptionPassword(StorageManager.CRYPT_TYPE_DEFAULT, null);
Robin Leed39113e2016-01-22 15:44:49 +0000514 setCredentialRequiredToDecrypt(false);
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100515 }
516
517 getDevicePolicyManager().setActivePasswordState(
518 DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, 0, 0, 0, 0, 0, 0, 0, userHandle);
519
Adrian Roosf8f56bc2014-11-20 23:55:34 +0100520 onAfterChangingPassword(userHandle);
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800521 }
Jim Miller5b0fb3a2010-02-23 13:46:35 -0800522
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800523 /**
Benjamin Franz51ed7942015-04-07 16:34:56 +0100524 * Disable showing lock screen at all for a given user.
525 * This is only meaningful if pattern, pin or password are not set.
Jim Miller2a98a4c2010-11-19 18:49:26 -0800526 *
Benjamin Franz51ed7942015-04-07 16:34:56 +0100527 * @param disable Disables lock screen when true
528 * @param userId User ID of the user this has effect on
529 */
530 public void setLockScreenDisabled(boolean disable, int userId) {
531 setBoolean(DISABLE_LOCKSCREEN_KEY, disable, userId);
532 }
533
534 /**
535 * Determine if LockScreen is disabled for the current user. This is used to decide whether
536 * LockScreen is shown after reboot or after screen timeout / short press on power.
537 *
538 * @return true if lock screen is disabled
Jim Miller2a98a4c2010-11-19 18:49:26 -0800539 */
Adrian Roos8150d2a2015-04-16 17:11:20 -0700540 public boolean isLockScreenDisabled(int userId) {
541 return !isSecure(userId) &&
542 getBoolean(DISABLE_LOCKSCREEN_KEY, false, userId);
Jim Miller2a98a4c2010-11-19 18:49:26 -0800543 }
544
545 /**
Jim Miller6edf2632011-09-05 16:03:14 -0700546 * Save a lock pattern.
547 * @param pattern The new pattern to save.
Adrian Roos8150d2a2015-04-16 17:11:20 -0700548 * @param userId the user whose pattern is to be saved.
Danielle Millett2364a222011-12-21 17:02:32 -0500549 */
Andres Morales8fa56652015-03-31 09:19:50 -0700550 public void saveLockPattern(List<LockPatternView.Cell> pattern, int userId) {
551 this.saveLockPattern(pattern, null, userId);
552 }
Danielle Millett2364a222011-12-21 17:02:32 -0500553 /**
554 * Save a lock pattern.
555 * @param pattern The new pattern to save.
Andres Morales8fa56652015-03-31 09:19:50 -0700556 * @param savedPattern The previously saved pattern, converted to String format
Adrian Roosf8f56bc2014-11-20 23:55:34 +0100557 * @param userId the user whose pattern is to be saved.
558 */
Andres Morales8fa56652015-03-31 09:19:50 -0700559 public void saveLockPattern(List<LockPatternView.Cell> pattern, String savedPattern, int userId) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800560 try {
Adrian Roosf80e66ce92015-01-15 23:27:24 +0100561 if (pattern == null || pattern.size() < MIN_LOCK_PATTERN_SIZE) {
562 throw new IllegalArgumentException("pattern must not be null and at least "
563 + MIN_LOCK_PATTERN_SIZE + " dots long.");
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100564 }
565
Andres Morales8fa56652015-03-31 09:19:50 -0700566 getLockSettings().setLockPattern(patternToString(pattern), savedPattern, userId);
Dianne Hackborn2509d3c2010-03-08 12:54:25 -0800567 DevicePolicyManager dpm = getDevicePolicyManager();
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100568
569 // Update the device encryption password.
Xiaohui Chen86c69dd2015-08-27 15:44:02 -0700570 if (userId == UserHandle.USER_SYSTEM
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100571 && LockPatternUtils.isDeviceEncryptionEnabled()) {
Andrei Kapishnikov4eb6a362015-04-02 15:21:20 -0400572 if (!shouldEncryptWithCredentials(true)) {
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100573 clearEncryptionPassword();
574 } else {
575 String stringPattern = patternToString(pattern);
576 updateEncryptionPassword(StorageManager.CRYPT_TYPE_PATTERN, stringPattern);
Paul Lawrence8e397362014-01-27 15:22:30 -0800577 }
Jim Miller31f90b62010-01-20 13:35:20 -0800578 }
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100579
580 setBoolean(PATTERN_EVER_CHOSEN_KEY, true, userId);
581
582 setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING, userId);
583 dpm.setActivePasswordState(DevicePolicyManager.PASSWORD_QUALITY_SOMETHING,
584 pattern.size(), 0, 0, 0, 0, 0, 0, userId);
Adrian Roosf8f56bc2014-11-20 23:55:34 +0100585 onAfterChangingPassword(userId);
Amith Yamasani52c489c2012-03-28 11:42:42 -0700586 } catch (RemoteException re) {
587 Log.e(TAG, "Couldn't save lock pattern " + re);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800588 }
589 }
590
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100591 private void updateCryptoUserInfo(int userId) {
Xiaohui Chen86c69dd2015-08-27 15:44:02 -0700592 if (userId != UserHandle.USER_SYSTEM) {
Paul Lawrencee51dcf92014-03-18 10:56:00 -0700593 return;
594 }
595
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100596 final String ownerInfo = isOwnerInfoEnabled(userId) ? getOwnerInfo(userId) : "";
Paul Lawrencee51dcf92014-03-18 10:56:00 -0700597
598 IBinder service = ServiceManager.getService("mount");
599 if (service == null) {
600 Log.e(TAG, "Could not find the mount service to update the user info");
601 return;
602 }
603
604 IMountService mountService = IMountService.Stub.asInterface(service);
605 try {
606 Log.d(TAG, "Setting owner info");
Elliott Hughesf839b4f2014-09-26 12:30:47 -0700607 mountService.setField(StorageManager.OWNER_INFO_KEY, ownerInfo);
Paul Lawrencee51dcf92014-03-18 10:56:00 -0700608 } catch (RemoteException e) {
609 Log.e(TAG, "Error changing user info", e);
610 }
611 }
612
Jim Miller187ec582013-04-15 18:27:54 -0700613 public void setOwnerInfo(String info, int userId) {
614 setString(LOCK_SCREEN_OWNER_INFO, info, userId);
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100615 updateCryptoUserInfo(userId);
Jim Miller187ec582013-04-15 18:27:54 -0700616 }
617
Adrian Roos8150d2a2015-04-16 17:11:20 -0700618 public void setOwnerInfoEnabled(boolean enabled, int userId) {
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100619 setBoolean(LOCK_SCREEN_OWNER_INFO_ENABLED, enabled, userId);
620 updateCryptoUserInfo(userId);
Jim Miller187ec582013-04-15 18:27:54 -0700621 }
622
623 public String getOwnerInfo(int userId) {
Adrian Roosdce01222015-01-07 22:39:01 +0100624 return getString(LOCK_SCREEN_OWNER_INFO, userId);
Jim Miller187ec582013-04-15 18:27:54 -0700625 }
626
Adrian Roos8150d2a2015-04-16 17:11:20 -0700627 public boolean isOwnerInfoEnabled(int userId) {
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100628 return getBoolean(LOCK_SCREEN_OWNER_INFO_ENABLED, false, userId);
Jim Miller187ec582013-04-15 18:27:54 -0700629 }
630
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800631 /**
Andrei Stingaceanu6644cd92015-11-10 13:03:31 +0000632 * Sets the device owner information. If the information is {@code null} or empty then the
633 * device owner info is cleared.
634 *
635 * @param info Device owner information which will be displayed instead of the user
636 * owner info.
637 */
638 public void setDeviceOwnerInfo(String info) {
639 if (info != null && info.isEmpty()) {
640 info = null;
641 }
642
643 setString(LOCK_SCREEN_DEVICE_OWNER_INFO, info, UserHandle.USER_SYSTEM);
644 }
645
646 public String getDeviceOwnerInfo() {
647 return getString(LOCK_SCREEN_DEVICE_OWNER_INFO, UserHandle.USER_SYSTEM);
648 }
649
650 public boolean isDeviceOwnerInfoEnabled() {
651 return getDeviceOwnerInfo() != null;
652 }
653
654 /**
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700655 * Compute the password quality from the given password string.
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800656 */
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700657 static public int computePasswordQuality(String password) {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800658 boolean hasDigit = false;
659 boolean hasNonDigit = false;
660 final int len = password.length();
661 for (int i = 0; i < len; i++) {
662 if (Character.isDigit(password.charAt(i))) {
663 hasDigit = true;
664 } else {
665 hasNonDigit = true;
666 }
667 }
Jim Miller5b0fb3a2010-02-23 13:46:35 -0800668
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700669 if (hasNonDigit && hasDigit) {
670 return DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC;
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800671 }
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800672 if (hasNonDigit) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700673 return DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC;
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800674 }
675 if (hasDigit) {
Jim Miller85516d02014-01-31 17:08:37 -0800676 return maxLengthSequence(password) > MAX_ALLOWED_SEQUENCE
677 ? DevicePolicyManager.PASSWORD_QUALITY_NUMERIC
678 : DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX;
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800679 }
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700680 return DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800681 }
Jim Miller5b0fb3a2010-02-23 13:46:35 -0800682
Jim Miller85516d02014-01-31 17:08:37 -0800683 private static int categoryChar(char c) {
684 if ('a' <= c && c <= 'z') return 0;
685 if ('A' <= c && c <= 'Z') return 1;
686 if ('0' <= c && c <= '9') return 2;
687 return 3;
688 }
689
690 private static int maxDiffCategory(int category) {
691 if (category == 0 || category == 1) return 1;
692 else if (category == 2) return 10;
693 return 0;
694 }
695
696 /*
697 * Returns the maximum length of a sequential characters. A sequence is defined as
698 * monotonically increasing characters with a constant interval or the same character repeated.
699 *
700 * For example:
701 * maxLengthSequence("1234") == 4
702 * maxLengthSequence("1234abc") == 4
703 * maxLengthSequence("aabc") == 3
704 * maxLengthSequence("qwertyuio") == 1
705 * maxLengthSequence("@ABC") == 3
706 * maxLengthSequence(";;;;") == 4 (anything that repeats)
707 * maxLengthSequence(":;<=>") == 1 (ordered, but not composed of alphas or digits)
708 *
709 * @param string the pass
710 * @return the number of sequential letters or digits
711 */
712 public static int maxLengthSequence(String string) {
713 if (string.length() == 0) return 0;
714 char previousChar = string.charAt(0);
715 int category = categoryChar(previousChar); //current category of the sequence
716 int diff = 0; //difference between two consecutive characters
717 boolean hasDiff = false; //if we are currently targeting a sequence
718 int maxLength = 0; //maximum length of a sequence already found
719 int startSequence = 0; //where the current sequence started
720 for (int current = 1; current < string.length(); current++) {
721 char currentChar = string.charAt(current);
722 int categoryCurrent = categoryChar(currentChar);
723 int currentDiff = (int) currentChar - (int) previousChar;
724 if (categoryCurrent != category || Math.abs(currentDiff) > maxDiffCategory(category)) {
725 maxLength = Math.max(maxLength, current - startSequence);
726 startSequence = current;
727 hasDiff = false;
728 category = categoryCurrent;
729 }
730 else {
731 if(hasDiff && currentDiff != diff) {
732 maxLength = Math.max(maxLength, current - startSequence);
733 startSequence = current - 1;
734 }
735 diff = currentDiff;
736 hasDiff = true;
737 }
738 previousChar = currentChar;
739 }
740 maxLength = Math.max(maxLength, string.length() - startSequence);
741 return maxLength;
742 }
743
Jason parksf7b3cd42011-01-27 09:28:25 -0600744 /** Update the encryption password if it is enabled **/
Paul Lawrence3a5a0be2014-09-25 09:26:34 -0700745 private void updateEncryptionPassword(final int type, final String password) {
Amith Yamasanicd410ba2014-10-17 11:16:58 -0700746 if (!isDeviceEncryptionEnabled()) {
Jason parksf7b3cd42011-01-27 09:28:25 -0600747 return;
748 }
Paul Lawrence3a5a0be2014-09-25 09:26:34 -0700749 final IBinder service = ServiceManager.getService("mount");
Jason parksf7b3cd42011-01-27 09:28:25 -0600750 if (service == null) {
751 Log.e(TAG, "Could not find the mount service to update the encryption password");
752 return;
753 }
754
Paul Lawrence3a5a0be2014-09-25 09:26:34 -0700755 new AsyncTask<Void, Void, Void>() {
756 @Override
757 protected Void doInBackground(Void... dummy) {
758 IMountService mountService = IMountService.Stub.asInterface(service);
759 try {
760 mountService.changeEncryptionPassword(type, password);
761 } catch (RemoteException e) {
762 Log.e(TAG, "Error changing encryption password", e);
763 }
764 return null;
765 }
766 }.execute();
Jason parksf7b3cd42011-01-27 09:28:25 -0600767 }
768
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800769 /**
Jim Millercd709882010-03-25 18:24:02 -0700770 * Save a lock password. Does not ensure that the password is as good
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800771 * as the requested mode, but will adjust the mode to be as good as the
Adrian Roos8150d2a2015-04-16 17:11:20 -0700772 * password.
Jim Miller69aa4a92009-12-22 19:03:28 -0800773 * @param password The password to save
Andres Morales8fa56652015-03-31 09:19:50 -0700774 * @param savedPassword The previously saved lock password, or null if none
Jim Millercd709882010-03-25 18:24:02 -0700775 * @param quality {@see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)}
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700776 * @param userHandle The userId of the user to change the password for
777 */
Andres Morales8fa56652015-03-31 09:19:50 -0700778 public void saveLockPassword(String password, String savedPassword, int quality,
779 int userHandle) {
Jim Miller69aa4a92009-12-22 19:03:28 -0800780 try {
Dianne Hackborn2509d3c2010-03-08 12:54:25 -0800781 DevicePolicyManager dpm = getDevicePolicyManager();
Adrian Roosf80e66ce92015-01-15 23:27:24 +0100782 if (password == null || password.length() < MIN_LOCK_PASSWORD_SIZE) {
783 throw new IllegalArgumentException("password must not be null and at least "
784 + "of length " + MIN_LOCK_PASSWORD_SIZE);
Jim Miller31f90b62010-01-20 13:35:20 -0800785 }
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100786
Andres Morales8fa56652015-03-31 09:19:50 -0700787 getLockSettings().setLockPassword(password, savedPassword, userHandle);
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100788 int computedQuality = computePasswordQuality(password);
789
790 // Update the device encryption password.
Xiaohui Chen86c69dd2015-08-27 15:44:02 -0700791 if (userHandle == UserHandle.USER_SYSTEM
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100792 && LockPatternUtils.isDeviceEncryptionEnabled()) {
Andrei Kapishnikov4eb6a362015-04-02 15:21:20 -0400793 if (!shouldEncryptWithCredentials(true)) {
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100794 clearEncryptionPassword();
795 } else {
796 boolean numeric = computedQuality
797 == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC;
798 boolean numericComplex = computedQuality
799 == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX;
800 int type = numeric || numericComplex ? StorageManager.CRYPT_TYPE_PIN
801 : StorageManager.CRYPT_TYPE_PASSWORD;
802 updateEncryptionPassword(type, password);
803 }
804 }
805
806 setLong(PASSWORD_TYPE_KEY, Math.max(quality, computedQuality), userHandle);
807 if (computedQuality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
808 int letters = 0;
809 int uppercase = 0;
810 int lowercase = 0;
811 int numbers = 0;
812 int symbols = 0;
813 int nonletter = 0;
814 for (int i = 0; i < password.length(); i++) {
815 char c = password.charAt(i);
816 if (c >= 'A' && c <= 'Z') {
817 letters++;
818 uppercase++;
819 } else if (c >= 'a' && c <= 'z') {
820 letters++;
821 lowercase++;
822 } else if (c >= '0' && c <= '9') {
823 numbers++;
824 nonletter++;
825 } else {
826 symbols++;
827 nonletter++;
828 }
829 }
830 dpm.setActivePasswordState(Math.max(quality, computedQuality),
831 password.length(), letters, uppercase, lowercase,
832 numbers, symbols, nonletter, userHandle);
833 } else {
834 // The password is not anything.
835 dpm.setActivePasswordState(
836 DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED,
837 0, 0, 0, 0, 0, 0, 0, userHandle);
838 }
839
840 // Add the password to the password history. We assume all
841 // password hashes have the same length for simplicity of implementation.
842 String passwordHistory = getString(PASSWORD_HISTORY_KEY, userHandle);
843 if (passwordHistory == null) {
844 passwordHistory = "";
845 }
846 int passwordHistoryLength = getRequestedPasswordHistoryLength(userHandle);
847 if (passwordHistoryLength == 0) {
848 passwordHistory = "";
849 } else {
850 byte[] hash = passwordToHash(password, userHandle);
851 passwordHistory = new String(hash, StandardCharsets.UTF_8) + "," + passwordHistory;
852 // Cut it to contain passwordHistoryLength hashes
853 // and passwordHistoryLength -1 commas.
854 passwordHistory = passwordHistory.substring(0, Math.min(hash.length
855 * passwordHistoryLength + passwordHistoryLength - 1, passwordHistory
856 .length()));
857 }
858 setString(PASSWORD_HISTORY_KEY, passwordHistory, userHandle);
Adrian Roosf8f56bc2014-11-20 23:55:34 +0100859 onAfterChangingPassword(userHandle);
Amith Yamasani52c489c2012-03-28 11:42:42 -0700860 } catch (RemoteException re) {
Jim Miller69aa4a92009-12-22 19:03:28 -0800861 // Cant do much
Amith Yamasani52c489c2012-03-28 11:42:42 -0700862 Log.e(TAG, "Unable to save lock password " + re);
Jim Miller69aa4a92009-12-22 19:03:28 -0800863 }
864 }
865
Jim Millercd709882010-03-25 18:24:02 -0700866 /**
Svetoslav16e4a1a2014-09-29 18:16:20 -0700867 * Gets whether the device is encrypted.
868 *
869 * @return Whether the device is encrypted.
870 */
871 public static boolean isDeviceEncrypted() {
872 IMountService mountService = IMountService.Stub.asInterface(
873 ServiceManager.getService("mount"));
874 try {
875 return mountService.getEncryptionState() != IMountService.ENCRYPTION_STATE_NONE
876 && mountService.getPasswordType() != StorageManager.CRYPT_TYPE_DEFAULT;
877 } catch (RemoteException re) {
878 Log.e(TAG, "Error getting encryption state", re);
879 }
880 return true;
881 }
882
883 /**
Jim Miller6848dc82014-10-13 18:51:53 -0700884 * Determine if the device supports encryption, even if it's set to default. This
885 * differs from isDeviceEncrypted() in that it returns true even if the device is
886 * encrypted with the default password.
887 * @return true if device encryption is enabled
888 */
889 public static boolean isDeviceEncryptionEnabled() {
890 final String status = SystemProperties.get("ro.crypto.state", "unsupported");
891 return "encrypted".equalsIgnoreCase(status);
892 }
893
894 /**
Paul Lawrence5c21c702016-01-29 13:26:19 -0800895 * Determine if the device is file encrypted
896 * @return true if device is file encrypted
897 */
898 public static boolean isFileEncryptionEnabled() {
Jeff Sharkeyde2dabb2016-02-29 17:12:34 -0700899 return StorageManager.isFileBasedEncryptionEnabled();
Paul Lawrence5c21c702016-01-29 13:26:19 -0800900 }
901
902 /**
Svetoslav16e4a1a2014-09-29 18:16:20 -0700903 * Clears the encryption password.
904 */
905 public void clearEncryptionPassword() {
906 updateEncryptionPassword(StorageManager.CRYPT_TYPE_DEFAULT, null);
907 }
908
909 /**
Adrian Roos1572ee32014-09-01 16:24:32 +0200910 * Retrieves the quality mode for {@param userHandle}.
911 * {@see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)}
912 *
913 * @return stored password quality
914 */
915 public int getKeyguardStoredPasswordQuality(int userHandle) {
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100916 return (int) getLong(PASSWORD_TYPE_KEY,
Adrian Roos1572ee32014-09-01 16:24:32 +0200917 DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, userHandle);
Jim Miller6edf2632011-09-05 16:03:14 -0700918 }
919
Danielle Millett58396982011-09-30 13:55:07 -0400920 /**
Clara Bayarria1771112015-12-18 16:29:18 +0000921 * Enables/disables the Separate Profile Challenge for this {@param userHandle}. This is a no-op
922 * for user handles that do not belong to a managed profile.
923 */
924 public void setSeparateProfileChallengeEnabled(int userHandle, boolean enabled) {
925 UserInfo info = getUserManager().getUserInfo(userHandle);
926 if (info.isManagedProfile()) {
927 setBoolean(SEPARATE_PROFILE_CHALLENGE_KEY, enabled, userHandle);
928 }
929 }
930
931 /**
932 * Retrieves whether the Separate Profile Challenge is enabled for this {@param userHandle}.
933 */
934 public boolean isSeparateProfileChallengeEnabled(int userHandle) {
935 UserInfo info = getUserManager().getUserInfo(userHandle);
Clara Bayarri8d35de82016-01-12 17:29:29 +0000936 if (info == null || !info.isManagedProfile()) {
Clara Bayarria1771112015-12-18 16:29:18 +0000937 return false;
938 }
939 return getBoolean(SEPARATE_PROFILE_CHALLENGE_KEY, false, userHandle);
940 }
941
942 /**
943 * Retrieves whether the current DPM allows use of the Profile Challenge.
944 */
945 public boolean isSeparateProfileChallengeAllowed(int userHandle) {
946 UserInfo info = getUserManager().getUserInfo(userHandle);
Clara Bayarri8d35de82016-01-12 17:29:29 +0000947 if (info == null || !info.isManagedProfile()) {
Clara Bayarria1771112015-12-18 16:29:18 +0000948 return false;
949 }
950 return getDevicePolicyManager().isSeparateProfileChallengeAllowed(userHandle);
951 }
952
953 /**
Clara Bayarrid7693912016-01-22 17:26:31 +0000954 * Retrieves whether the current profile and device locks can be unified.
955 */
956 public boolean isSeparateProfileChallengeAllowedToUnify(int userHandle) {
957 return getDevicePolicyManager().isProfileActivePasswordSufficientForParent(userHandle);
958 }
959
960 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800961 * Deserialize a pattern.
962 * @param string The pattern serialized with {@link #patternToString}
963 * @return The pattern.
964 */
965 public static List<LockPatternView.Cell> stringToPattern(String string) {
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100966 if (string == null) {
967 return null;
968 }
969
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800970 List<LockPatternView.Cell> result = Lists.newArrayList();
971
972 final byte[] bytes = string.getBytes();
973 for (int i = 0; i < bytes.length; i++) {
Andres Moralese40bad82015-05-28 14:21:36 -0700974 byte b = (byte) (bytes[i] - '1');
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800975 result.add(LockPatternView.Cell.of(b / 3, b % 3));
976 }
977 return result;
978 }
979
980 /**
981 * Serialize a pattern.
982 * @param pattern The pattern.
983 * @return The pattern in string form.
984 */
985 public static String patternToString(List<LockPatternView.Cell> pattern) {
986 if (pattern == null) {
987 return "";
988 }
989 final int patternSize = pattern.size();
990
991 byte[] res = new byte[patternSize];
992 for (int i = 0; i < patternSize; i++) {
993 LockPatternView.Cell cell = pattern.get(i);
Andres Moralese40bad82015-05-28 14:21:36 -0700994 res[i] = (byte) (cell.getRow() * 3 + cell.getColumn() + '1');
995 }
996 return new String(res);
997 }
998
999 public static String patternStringToBaseZero(String pattern) {
1000 if (pattern == null) {
1001 return "";
1002 }
1003 final int patternSize = pattern.length();
1004
1005 byte[] res = new byte[patternSize];
1006 final byte[] bytes = pattern.getBytes();
1007 for (int i = 0; i < patternSize; i++) {
1008 res[i] = (byte) (bytes[i] - '1');
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001009 }
1010 return new String(res);
1011 }
Jim Miller69aa4a92009-12-22 19:03:28 -08001012
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001013 /*
1014 * Generate an SHA-1 hash for the pattern. Not the most secure, but it is
1015 * at least a second level of protection. First level is that the file
1016 * is in a location only readable by the system process.
1017 * @param pattern the gesture pattern.
1018 * @return the hash of the pattern in a byte array.
1019 */
Jim Millerde1af082013-09-11 14:58:26 -07001020 public static byte[] patternToHash(List<LockPatternView.Cell> pattern) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001021 if (pattern == null) {
1022 return null;
1023 }
Jim Miller69aa4a92009-12-22 19:03:28 -08001024
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001025 final int patternSize = pattern.size();
1026 byte[] res = new byte[patternSize];
1027 for (int i = 0; i < patternSize; i++) {
1028 LockPatternView.Cell cell = pattern.get(i);
1029 res[i] = (byte) (cell.getRow() * 3 + cell.getColumn());
1030 }
1031 try {
1032 MessageDigest md = MessageDigest.getInstance("SHA-1");
1033 byte[] hash = md.digest(res);
1034 return hash;
1035 } catch (NoSuchAlgorithmException nsa) {
1036 return res;
1037 }
1038 }
1039
Geoffrey Borggaard987672d22014-07-18 16:47:18 -04001040 private String getSalt(int userId) {
1041 long salt = getLong(LOCK_PASSWORD_SALT_KEY, 0, userId);
Jim Miller11b019d2010-01-20 16:34:45 -08001042 if (salt == 0) {
1043 try {
1044 salt = SecureRandom.getInstance("SHA1PRNG").nextLong();
Geoffrey Borggaard987672d22014-07-18 16:47:18 -04001045 setLong(LOCK_PASSWORD_SALT_KEY, salt, userId);
1046 Log.v(TAG, "Initialized lock password salt for user: " + userId);
Jim Miller11b019d2010-01-20 16:34:45 -08001047 } catch (NoSuchAlgorithmException e) {
1048 // Throw an exception rather than storing a password we'll never be able to recover
1049 throw new IllegalStateException("Couldn't get SecureRandom number", e);
1050 }
1051 }
1052 return Long.toHexString(salt);
1053 }
1054
Jim Miller69aa4a92009-12-22 19:03:28 -08001055 /*
1056 * Generate a hash for the given password. To avoid brute force attacks, we use a salted hash.
1057 * Not the most secure, but it is at least a second level of protection. First level is that
1058 * the file is in a location only readable by the system process.
Narayan Kamath78108a32014-12-16 12:56:23 +00001059 *
Jim Miller69aa4a92009-12-22 19:03:28 -08001060 * @param password the gesture pattern.
Narayan Kamath78108a32014-12-16 12:56:23 +00001061 *
Jim Miller69aa4a92009-12-22 19:03:28 -08001062 * @return the hash of the pattern in a byte array.
1063 */
Geoffrey Borggaard987672d22014-07-18 16:47:18 -04001064 public byte[] passwordToHash(String password, int userId) {
Jim Miller69aa4a92009-12-22 19:03:28 -08001065 if (password == null) {
1066 return null;
1067 }
Narayan Kamath78108a32014-12-16 12:56:23 +00001068
Jim Miller69aa4a92009-12-22 19:03:28 -08001069 try {
Geoffrey Borggaard987672d22014-07-18 16:47:18 -04001070 byte[] saltedPassword = (password + getSalt(userId)).getBytes();
Narayan Kamath78108a32014-12-16 12:56:23 +00001071 byte[] sha1 = MessageDigest.getInstance("SHA-1").digest(saltedPassword);
1072 byte[] md5 = MessageDigest.getInstance("MD5").digest(saltedPassword);
Jim Miller69aa4a92009-12-22 19:03:28 -08001073
Narayan Kamath78108a32014-12-16 12:56:23 +00001074 byte[] combined = new byte[sha1.length + md5.length];
1075 System.arraycopy(sha1, 0, combined, 0, sha1.length);
1076 System.arraycopy(md5, 0, combined, sha1.length, md5.length);
1077
1078 final char[] hexEncoded = HexEncoding.encode(combined);
1079 return new String(hexEncoded).getBytes(StandardCharsets.UTF_8);
1080 } catch (NoSuchAlgorithmException e) {
1081 throw new AssertionError("Missing digest algorithm: ", e);
Jim Miller69aa4a92009-12-22 19:03:28 -08001082 }
Jim Miller69aa4a92009-12-22 19:03:28 -08001083 }
1084
1085 /**
Adrian Roos9dd16eb2015-01-08 16:20:49 +01001086 * @param userId the user for which to report the value
1087 * @return Whether the lock screen is secured.
1088 */
1089 public boolean isSecure(int userId) {
1090 int mode = getKeyguardStoredPasswordQuality(userId);
1091 return isLockPatternEnabled(mode, userId) || isLockPasswordEnabled(mode, userId);
1092 }
1093
Adrian Roosdce01222015-01-07 22:39:01 +01001094 public boolean isLockPasswordEnabled(int userId) {
Adrian Roos9dd16eb2015-01-08 16:20:49 +01001095 return isLockPasswordEnabled(getKeyguardStoredPasswordQuality(userId), userId);
1096 }
1097
1098 private boolean isLockPasswordEnabled(int mode, int userId) {
Danielle Millett73da5fe2011-09-13 16:20:05 -04001099 final boolean passwordEnabled = mode == DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC
1100 || mode == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC
Jim Miller85516d02014-01-31 17:08:37 -08001101 || mode == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX
Danielle Millett73da5fe2011-09-13 16:20:05 -04001102 || mode == DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC
1103 || mode == DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
Adrian Roos9dd16eb2015-01-08 16:20:49 +01001104 return passwordEnabled && savedPasswordExists(userId);
Jim Miller69aa4a92009-12-22 19:03:28 -08001105 }
1106
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001107 /**
Adrian Roos230635e2015-01-07 20:50:29 +01001108 * @return Whether the lock pattern is enabled
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001109 */
Adrian Roos50bfeec2014-11-20 16:21:11 +01001110 public boolean isLockPatternEnabled(int userId) {
Adrian Roos9dd16eb2015-01-08 16:20:49 +01001111 return isLockPatternEnabled(getKeyguardStoredPasswordQuality(userId), userId);
Danielle Millett925a7d82012-03-19 18:02:20 -04001112 }
1113
Bryce Lee46145962015-12-14 14:39:10 -08001114 @Deprecated
1115 public boolean isLegacyLockPatternEnabled(int userId) {
1116 // Note: this value should default to {@code true} to avoid any reset that might result.
1117 // We must use a special key to read this value, since it will by default return the value
1118 // based on the new logic.
1119 return getBoolean(LEGACY_LOCK_PATTERN_ENABLED, true, userId);
1120 }
1121
1122 @Deprecated
1123 public void setLegacyLockPatternEnabled(int userId) {
1124 setBoolean(Settings.Secure.LOCK_PATTERN_ENABLED, true, userId);
1125 }
1126
Adrian Roos9dd16eb2015-01-08 16:20:49 +01001127 private boolean isLockPatternEnabled(int mode, int userId) {
1128 return mode == DevicePolicyManager.PASSWORD_QUALITY_SOMETHING
1129 && savedPatternExists(userId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001130 }
1131
1132 /**
1133 * @return Whether the visible pattern is enabled.
1134 */
Adrian Roos8150d2a2015-04-16 17:11:20 -07001135 public boolean isVisiblePatternEnabled(int userId) {
1136 return getBoolean(Settings.Secure.LOCK_PATTERN_VISIBLE, false, userId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001137 }
1138
1139 /**
1140 * Set whether the visible pattern is enabled.
1141 */
Adrian Roos8150d2a2015-04-16 17:11:20 -07001142 public void setVisiblePatternEnabled(boolean enabled, int userId) {
Adrian Roosdce01222015-01-07 22:39:01 +01001143 setBoolean(Settings.Secure.LOCK_PATTERN_VISIBLE, enabled, userId);
Paul Lawrence878ba0a2014-08-20 13:08:01 -07001144
1145 // Update for crypto if owner
Xiaohui Chen86c69dd2015-08-27 15:44:02 -07001146 if (userId != UserHandle.USER_SYSTEM) {
Paul Lawrence878ba0a2014-08-20 13:08:01 -07001147 return;
1148 }
1149
1150 IBinder service = ServiceManager.getService("mount");
1151 if (service == null) {
1152 Log.e(TAG, "Could not find the mount service to update the user info");
1153 return;
1154 }
1155
1156 IMountService mountService = IMountService.Stub.asInterface(service);
1157 try {
Elliott Hughesf839b4f2014-09-26 12:30:47 -07001158 mountService.setField(StorageManager.PATTERN_VISIBLE_KEY, enabled ? "1" : "0");
Paul Lawrence878ba0a2014-08-20 13:08:01 -07001159 } catch (RemoteException e) {
1160 Log.e(TAG, "Error changing pattern visible state", e);
1161 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001162 }
1163
1164 /**
Paul Lawrenced8fdb332015-05-18 13:26:11 -07001165 * Set whether the visible password is enabled for cryptkeeper screen.
1166 */
1167 public void setVisiblePasswordEnabled(boolean enabled, int userId) {
1168 // Update for crypto if owner
Xiaohui Chen86c69dd2015-08-27 15:44:02 -07001169 if (userId != UserHandle.USER_SYSTEM) {
Paul Lawrenced8fdb332015-05-18 13:26:11 -07001170 return;
1171 }
1172
1173 IBinder service = ServiceManager.getService("mount");
1174 if (service == null) {
1175 Log.e(TAG, "Could not find the mount service to update the user info");
1176 return;
1177 }
1178
1179 IMountService mountService = IMountService.Stub.asInterface(service);
1180 try {
1181 mountService.setField(StorageManager.PASSWORD_VISIBLE_KEY, enabled ? "1" : "0");
1182 } catch (RemoteException e) {
1183 Log.e(TAG, "Error changing password visible state", e);
1184 }
1185 }
1186
1187 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001188 * @return Whether tactile feedback for the pattern is enabled.
1189 */
1190 public boolean isTactileFeedbackEnabled() {
Jeff Sharkey5ed9d682012-10-10 14:28:27 -07001191 return Settings.System.getIntForUser(mContentResolver,
1192 Settings.System.HAPTIC_FEEDBACK_ENABLED, 1, UserHandle.USER_CURRENT) != 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001193 }
1194
1195 /**
1196 * Set and store the lockout deadline, meaning the user can't attempt his/her unlock
1197 * pattern until the deadline has passed.
1198 * @return the chosen deadline.
1199 */
Andres Morales23974272015-05-14 22:42:26 -07001200 public long setLockoutAttemptDeadline(int userId, int timeoutMs) {
1201 final long deadline = SystemClock.elapsedRealtime() + timeoutMs;
Adrian Roos8150d2a2015-04-16 17:11:20 -07001202 setLong(LOCKOUT_ATTEMPT_DEADLINE, deadline, userId);
Andres Morales23974272015-05-14 22:42:26 -07001203 setLong(LOCKOUT_ATTEMPT_TIMEOUT_MS, timeoutMs, userId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001204 return deadline;
1205 }
1206
1207 /**
1208 * @return The elapsed time in millis in the future when the user is allowed to
1209 * attempt to enter his/her lock pattern, or 0 if the user is welcome to
1210 * enter a pattern.
1211 */
Adrian Roos8150d2a2015-04-16 17:11:20 -07001212 public long getLockoutAttemptDeadline(int userId) {
Andres Moralesa4e23372015-09-08 13:17:37 -07001213 long deadline = getLong(LOCKOUT_ATTEMPT_DEADLINE, 0L, userId);
Andres Morales23974272015-05-14 22:42:26 -07001214 final long timeoutMs = getLong(LOCKOUT_ATTEMPT_TIMEOUT_MS, 0L, userId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001215 final long now = SystemClock.elapsedRealtime();
Jorim Jaggie3e6d562015-09-28 13:57:37 -07001216 if (deadline < now && deadline != 0) {
Andres Moralesa4e23372015-09-08 13:17:37 -07001217 // timeout expired
1218 setLong(LOCKOUT_ATTEMPT_DEADLINE, 0, userId);
1219 setLong(LOCKOUT_ATTEMPT_TIMEOUT_MS, 0, userId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001220 return 0L;
1221 }
Andres Moralesa4e23372015-09-08 13:17:37 -07001222
1223 if (deadline > (now + timeoutMs)) {
1224 // device was rebooted, set new deadline
1225 deadline = now + timeoutMs;
1226 setLong(LOCKOUT_ATTEMPT_DEADLINE, deadline, userId);
1227 }
1228
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001229 return deadline;
1230 }
1231
Jim Millerf45bb402013-08-20 18:58:32 -07001232 private boolean getBoolean(String secureSettingKey, boolean defaultValue, int userId) {
Amith Yamasani52c489c2012-03-28 11:42:42 -07001233 try {
Jim Millerf45bb402013-08-20 18:58:32 -07001234 return getLockSettings().getBoolean(secureSettingKey, defaultValue, userId);
Amith Yamasani52c489c2012-03-28 11:42:42 -07001235 } catch (RemoteException re) {
1236 return defaultValue;
1237 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001238 }
1239
Jim Millerf45bb402013-08-20 18:58:32 -07001240 private void setBoolean(String secureSettingKey, boolean enabled, int userId) {
Amith Yamasani52c489c2012-03-28 11:42:42 -07001241 try {
Jim Millerf45bb402013-08-20 18:58:32 -07001242 getLockSettings().setBoolean(secureSettingKey, enabled, userId);
Amith Yamasani52c489c2012-03-28 11:42:42 -07001243 } catch (RemoteException re) {
1244 // What can we do?
1245 Log.e(TAG, "Couldn't write boolean " + secureSettingKey + re);
1246 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001247 }
1248
Geoffrey Borggaard987672d22014-07-18 16:47:18 -04001249 private long getLong(String secureSettingKey, long defaultValue, int userHandle) {
1250 try {
1251 return getLockSettings().getLong(secureSettingKey, defaultValue, userHandle);
1252 } catch (RemoteException re) {
1253 return defaultValue;
1254 }
1255 }
1256
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001257 private void setLong(String secureSettingKey, long value, int userHandle) {
Amith Yamasani52c489c2012-03-28 11:42:42 -07001258 try {
Kenny Guy0cf13702013-11-29 16:33:05 +00001259 getLockSettings().setLong(secureSettingKey, value, userHandle);
Amith Yamasani52c489c2012-03-28 11:42:42 -07001260 } catch (RemoteException re) {
1261 // What can we do?
1262 Log.e(TAG, "Couldn't write long " + secureSettingKey + re);
1263 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001264 }
1265
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001266 private String getString(String secureSettingKey, int userHandle) {
Amith Yamasani52c489c2012-03-28 11:42:42 -07001267 try {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001268 return getLockSettings().getString(secureSettingKey, null, userHandle);
Amith Yamasani52c489c2012-03-28 11:42:42 -07001269 } catch (RemoteException re) {
1270 return null;
1271 }
Konstantin Lopyrev863f22d2010-05-12 17:16:58 -07001272 }
1273
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001274 private void setString(String secureSettingKey, String value, int userHandle) {
Amith Yamasani52c489c2012-03-28 11:42:42 -07001275 try {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001276 getLockSettings().setString(secureSettingKey, value, userHandle);
Amith Yamasani52c489c2012-03-28 11:42:42 -07001277 } catch (RemoteException re) {
1278 // What can we do?
1279 Log.e(TAG, "Couldn't write string " + secureSettingKey + re);
1280 }
Konstantin Lopyrev863f22d2010-05-12 17:16:58 -07001281 }
1282
Adrian Roos8150d2a2015-04-16 17:11:20 -07001283 public void setPowerButtonInstantlyLocks(boolean enabled, int userId) {
1284 setBoolean(LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS, enabled, userId);
Jim Millera4edd152012-01-06 18:24:04 -08001285 }
1286
Adrian Roos8150d2a2015-04-16 17:11:20 -07001287 public boolean getPowerButtonInstantlyLocks(int userId) {
1288 return getBoolean(LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS, true, userId);
Adrian Roos82142c22014-03-27 14:56:59 +01001289 }
1290
1291 public void setEnabledTrustAgents(Collection<ComponentName> activeTrustAgents, int userId) {
1292 StringBuilder sb = new StringBuilder();
1293 for (ComponentName cn : activeTrustAgents) {
1294 if (sb.length() > 0) {
1295 sb.append(',');
1296 }
1297 sb.append(cn.flattenToShortString());
1298 }
1299 setString(ENABLED_TRUST_AGENTS, sb.toString(), userId);
Adrian Roos8150d2a2015-04-16 17:11:20 -07001300 getTrustManager().reportEnabledTrustAgentsChanged(userId);
Adrian Roos82142c22014-03-27 14:56:59 +01001301 }
1302
1303 public List<ComponentName> getEnabledTrustAgents(int userId) {
1304 String serialized = getString(ENABLED_TRUST_AGENTS, userId);
1305 if (TextUtils.isEmpty(serialized)) {
1306 return null;
1307 }
1308 String[] split = serialized.split(",");
1309 ArrayList<ComponentName> activeTrustAgents = new ArrayList<ComponentName>(split.length);
1310 for (String s : split) {
1311 if (!TextUtils.isEmpty(s)) {
1312 activeTrustAgents.add(ComponentName.unflattenFromString(s));
1313 }
1314 }
1315 return activeTrustAgents;
1316 }
Adrian Roos2c12cfa2014-06-25 23:28:53 +02001317
1318 /**
Adrian Roosb5e47222015-08-14 15:53:06 -07001319 * Disable trust until credentials have been entered for user {@param userId}.
1320 *
1321 * Requires the {@link android.Manifest.permission#ACCESS_KEYGUARD_SECURE_STORAGE} permission.
1322 *
1323 * @param userId either an explicit user id or {@link android.os.UserHandle#USER_ALL}
Adrian Roos2c12cfa2014-06-25 23:28:53 +02001324 */
1325 public void requireCredentialEntry(int userId) {
Jorim Jaggi16093fe32015-09-09 23:29:17 +00001326 requireStrongAuth(StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_USER_REQUEST, userId);
Adrian Roosb5e47222015-08-14 15:53:06 -07001327 }
1328
1329 /**
1330 * Requests strong authentication for user {@param userId}.
1331 *
1332 * Requires the {@link android.Manifest.permission#ACCESS_KEYGUARD_SECURE_STORAGE} permission.
1333 *
1334 * @param strongAuthReason a combination of {@link StrongAuthTracker.StrongAuthFlags} indicating
1335 * the reason for and the strength of the requested authentication.
1336 * @param userId either an explicit user id or {@link android.os.UserHandle#USER_ALL}
1337 */
1338 public void requireStrongAuth(@StrongAuthTracker.StrongAuthFlags int strongAuthReason,
1339 int userId) {
1340 try {
1341 getLockSettings().requireStrongAuth(strongAuthReason, userId);
1342 } catch (RemoteException e) {
1343 Log.e(TAG, "Error while requesting strong auth: " + e);
1344 }
Adrian Roos2c12cfa2014-06-25 23:28:53 +02001345 }
Adrian Roos4b9e3242014-08-20 23:36:25 +02001346
Adrian Roosf8f56bc2014-11-20 23:55:34 +01001347 private void onAfterChangingPassword(int userHandle) {
1348 getTrustManager().reportEnabledTrustAgentsChanged(userHandle);
Adrian Roos4b9e3242014-08-20 23:36:25 +02001349 }
Jim Millerdd5de712014-10-16 19:50:18 -07001350
1351 public boolean isCredentialRequiredToDecrypt(boolean defaultValue) {
1352 final int value = Settings.Global.getInt(mContentResolver,
1353 Settings.Global.REQUIRE_PASSWORD_TO_DECRYPT, -1);
1354 return value == -1 ? defaultValue : (value != 0);
1355 }
1356
1357 public void setCredentialRequiredToDecrypt(boolean required) {
Robin Leed39113e2016-01-22 15:44:49 +00001358 if (!(getUserManager().isSystemUser() || getUserManager().isPrimaryUser())) {
1359 throw new IllegalStateException(
1360 "Only the system or primary user may call setCredentialRequiredForDecrypt()");
Jim Millerdd5de712014-10-16 19:50:18 -07001361 }
Paul Lawrence688af6c2015-05-15 11:26:17 -07001362
1363 if (isDeviceEncryptionEnabled()){
1364 Settings.Global.putInt(mContext.getContentResolver(),
1365 Settings.Global.REQUIRE_PASSWORD_TO_DECRYPT, required ? 1 : 0);
1366 }
Jim Millerdd5de712014-10-16 19:50:18 -07001367 }
Andrei Kapishnikov4eb6a362015-04-02 15:21:20 -04001368
1369 private boolean isDoNotAskCredentialsOnBootSet() {
1370 return mDevicePolicyManager.getDoNotAskCredentialsOnBoot();
1371 }
1372
1373 private boolean shouldEncryptWithCredentials(boolean defaultValue) {
1374 return isCredentialRequiredToDecrypt(defaultValue) && !isDoNotAskCredentialsOnBootSet();
1375 }
Xiyuan Xiaaa262942015-05-05 15:18:45 -07001376
1377 private void throwIfCalledOnMainThread() {
1378 if (Looper.getMainLooper().isCurrentThread()) {
1379 throw new IllegalStateException("should not be called from the main thread.");
1380 }
1381 }
Adrian Roosb5e47222015-08-14 15:53:06 -07001382
1383 public void registerStrongAuthTracker(final StrongAuthTracker strongAuthTracker) {
1384 try {
1385 getLockSettings().registerStrongAuthTracker(strongAuthTracker.mStub);
1386 } catch (RemoteException e) {
1387 throw new RuntimeException("Could not register StrongAuthTracker");
1388 }
1389 }
1390
1391 public void unregisterStrongAuthTracker(final StrongAuthTracker strongAuthTracker) {
1392 try {
1393 getLockSettings().unregisterStrongAuthTracker(strongAuthTracker.mStub);
1394 } catch (RemoteException e) {
1395 Log.e(TAG, "Could not unregister StrongAuthTracker", e);
1396 }
1397 }
1398
1399 /**
1400 * Tracks the global strong authentication state.
1401 */
1402 public static class StrongAuthTracker {
1403
1404 @IntDef(flag = true,
1405 value = { STRONG_AUTH_NOT_REQUIRED,
1406 STRONG_AUTH_REQUIRED_AFTER_BOOT,
1407 STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW,
Jorim Jaggi16093fe32015-09-09 23:29:17 +00001408 SOME_AUTH_REQUIRED_AFTER_USER_REQUEST})
Adrian Roosb5e47222015-08-14 15:53:06 -07001409 @Retention(RetentionPolicy.SOURCE)
1410 public @interface StrongAuthFlags {}
1411
1412 /**
1413 * Strong authentication is not required.
1414 */
1415 public static final int STRONG_AUTH_NOT_REQUIRED = 0x0;
1416
1417 /**
1418 * Strong authentication is required because the user has not authenticated since boot.
1419 */
1420 public static final int STRONG_AUTH_REQUIRED_AFTER_BOOT = 0x1;
1421
1422 /**
Jorim Jaggi16093fe32015-09-09 23:29:17 +00001423 * Strong authentication is required because a device admin has requested it.
Adrian Roosb5e47222015-08-14 15:53:06 -07001424 */
1425 public static final int STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW = 0x2;
1426
1427 /**
Jorim Jaggi16093fe32015-09-09 23:29:17 +00001428 * Some authentication is required because the user has temporarily disabled trust.
Adrian Roosb5e47222015-08-14 15:53:06 -07001429 */
Jorim Jaggi16093fe32015-09-09 23:29:17 +00001430 public static final int SOME_AUTH_REQUIRED_AFTER_USER_REQUEST = 0x4;
Adrian Roosb5e47222015-08-14 15:53:06 -07001431
Adrian Roos873010d2015-08-25 15:59:00 -07001432 /**
1433 * Strong authentication is required because the user has been locked out after too many
1434 * attempts.
1435 */
1436 public static final int STRONG_AUTH_REQUIRED_AFTER_LOCKOUT = 0x8;
1437
Adrian Roosaf4ab3e2015-09-02 13:23:30 -07001438 /**
1439 * Some authentication is required because the user has entered a wrong credential.
1440 */
1441 public static final int SOME_AUTH_REQUIRED_AFTER_WRONG_CREDENTIAL = 0x10;
1442
Adrian Roosaf4ab3e2015-09-02 13:23:30 -07001443 private static final int ALLOWING_FINGERPRINT = STRONG_AUTH_NOT_REQUIRED
Jorim Jaggi16093fe32015-09-09 23:29:17 +00001444 | SOME_AUTH_REQUIRED_AFTER_USER_REQUEST
Adrian Roosaf4ab3e2015-09-02 13:23:30 -07001445 | SOME_AUTH_REQUIRED_AFTER_WRONG_CREDENTIAL;
Adrian Roosb5e47222015-08-14 15:53:06 -07001446
Adrian Roosaf4ab3e2015-09-02 13:23:30 -07001447 private final SparseIntArray mStrongAuthRequiredForUser = new SparseIntArray();
Adrian Roosb5e47222015-08-14 15:53:06 -07001448 private final H mHandler;
Rakesh Iyera7aa4d62016-01-19 17:27:23 -08001449 private final int mDefaultStrongAuthFlags;
Adrian Roosb5e47222015-08-14 15:53:06 -07001450
Rakesh Iyera7aa4d62016-01-19 17:27:23 -08001451 public StrongAuthTracker(Context context) {
1452 this(context, Looper.myLooper());
Adrian Roosb5e47222015-08-14 15:53:06 -07001453 }
1454
1455 /**
1456 * @param looper the looper on whose thread calls to {@link #onStrongAuthRequiredChanged}
1457 * will be scheduled.
Rakesh Iyera7aa4d62016-01-19 17:27:23 -08001458 * @param context the current {@link Context}
Adrian Roosb5e47222015-08-14 15:53:06 -07001459 */
Rakesh Iyera7aa4d62016-01-19 17:27:23 -08001460 public StrongAuthTracker(Context context, Looper looper) {
Adrian Roosb5e47222015-08-14 15:53:06 -07001461 mHandler = new H(looper);
Rakesh Iyera7aa4d62016-01-19 17:27:23 -08001462 mDefaultStrongAuthFlags = getDefaultFlags(context);
1463 }
1464
1465 public static @StrongAuthFlags int getDefaultFlags(Context context) {
1466 boolean strongAuthRequired = context.getResources().getBoolean(
1467 com.android.internal.R.bool.config_strongAuthRequiredOnBoot);
1468 return strongAuthRequired ? STRONG_AUTH_REQUIRED_AFTER_BOOT : STRONG_AUTH_NOT_REQUIRED;
Adrian Roosb5e47222015-08-14 15:53:06 -07001469 }
1470
1471 /**
1472 * Returns {@link #STRONG_AUTH_NOT_REQUIRED} if strong authentication is not required,
1473 * otherwise returns a combination of {@link StrongAuthFlags} indicating why strong
1474 * authentication is required.
1475 *
1476 * @param userId the user for whom the state is queried.
1477 */
1478 public @StrongAuthFlags int getStrongAuthForUser(int userId) {
Rakesh Iyera7aa4d62016-01-19 17:27:23 -08001479 return mStrongAuthRequiredForUser.get(userId, mDefaultStrongAuthFlags);
Adrian Roosb5e47222015-08-14 15:53:06 -07001480 }
1481
1482 /**
1483 * @return true if unlocking with trust alone is allowed for {@param userId} by the current
1484 * strong authentication requirements.
1485 */
1486 public boolean isTrustAllowedForUser(int userId) {
1487 return getStrongAuthForUser(userId) == STRONG_AUTH_NOT_REQUIRED;
1488 }
1489
1490 /**
1491 * @return true if unlocking with fingerprint alone is allowed for {@param userId} by the
1492 * current strong authentication requirements.
1493 */
1494 public boolean isFingerprintAllowedForUser(int userId) {
Adrian Roosaf4ab3e2015-09-02 13:23:30 -07001495 return (getStrongAuthForUser(userId) & ~ALLOWING_FINGERPRINT) == 0;
Adrian Roosb5e47222015-08-14 15:53:06 -07001496 }
1497
1498 /**
1499 * Called when the strong authentication requirements for {@param userId} changed.
1500 */
1501 public void onStrongAuthRequiredChanged(int userId) {
1502 }
1503
1504 void handleStrongAuthRequiredChanged(@StrongAuthFlags int strongAuthFlags,
1505 int userId) {
1506
1507 int oldValue = getStrongAuthForUser(userId);
1508 if (strongAuthFlags != oldValue) {
Rakesh Iyera7aa4d62016-01-19 17:27:23 -08001509 if (strongAuthFlags == mDefaultStrongAuthFlags) {
Adrian Roosb5e47222015-08-14 15:53:06 -07001510 mStrongAuthRequiredForUser.delete(userId);
1511 } else {
1512 mStrongAuthRequiredForUser.put(userId, strongAuthFlags);
1513 }
1514 onStrongAuthRequiredChanged(userId);
1515 }
1516 }
1517
1518
1519 final IStrongAuthTracker.Stub mStub = new IStrongAuthTracker.Stub() {
1520 @Override
1521 public void onStrongAuthRequiredChanged(@StrongAuthFlags int strongAuthFlags,
1522 int userId) {
1523 mHandler.obtainMessage(H.MSG_ON_STRONG_AUTH_REQUIRED_CHANGED,
1524 strongAuthFlags, userId).sendToTarget();
1525 }
1526 };
1527
1528 private class H extends Handler {
1529 static final int MSG_ON_STRONG_AUTH_REQUIRED_CHANGED = 1;
1530
1531 public H(Looper looper) {
1532 super(looper);
1533 }
1534
1535 @Override
1536 public void handleMessage(Message msg) {
1537 switch (msg.what) {
1538 case MSG_ON_STRONG_AUTH_REQUIRED_CHANGED:
1539 handleStrongAuthRequiredChanged(msg.arg1, msg.arg2);
1540 break;
1541 }
1542 }
1543 };
1544 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001545}