Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 284d9401 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Refactor LockSettingsService to unify the handling of pattern and password"

parents 1897b577 1de89b3b
Loading
Loading
Loading
Loading
+4 −8
Original line number Diff line number Diff line
@@ -28,16 +28,12 @@ interface ILockSettings {
    boolean getBoolean(in String key, in boolean defaultValue, in int userId);
    long getLong(in String key, in long defaultValue, in int userId);
    String getString(in String key, in String defaultValue, in int userId);
    void setLockPattern(in String pattern, in String savedPattern, int userId);
    void setLockCredential(in String credential, int type, in String savedCredential, int userId);
    void resetKeyStore(int userId);
    VerifyCredentialResponse checkPattern(in String pattern, int userId,
    VerifyCredentialResponse checkCredential(in String credential, int type, int userId,
            in ICheckCredentialProgressCallback progressCallback);
    VerifyCredentialResponse verifyPattern(in String pattern, long challenge, int userId);
    void setLockPassword(in String password, in String savedPassword, int userId);
    VerifyCredentialResponse checkPassword(in String password, int userId,
            in ICheckCredentialProgressCallback progressCallback);
    VerifyCredentialResponse verifyPassword(in String password, long challenge, int userId);
    VerifyCredentialResponse verifyTiedProfileChallenge(String password, boolean isPattern, long challenge, int userId);
    VerifyCredentialResponse verifyCredential(in String credential, int type, long challenge, int userId);
    VerifyCredentialResponse verifyTiedProfileChallenge(String credential, int type, long challenge, int userId);
    boolean checkVoldPassword(int userId);
    boolean havePattern(int userId);
    boolean havePassword(int userId);
+58 −69
Original line number Diff line number Diff line
@@ -45,6 +45,8 @@ import android.util.SparseIntArray;

import com.google.android.collect.Lists;

import libcore.util.HexEncoding;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.nio.charset.StandardCharsets;
@@ -55,8 +57,6 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import libcore.util.HexEncoding;

/**
 * Utilities for the lock pattern and its settings.
 */
@@ -66,7 +66,7 @@ public class LockPatternUtils {
    private static final boolean DEBUG = false;

    /**
     * The key to identify when the lock pattern enabled flag is being acccessed for legacy reasons.
     * The key to identify when the lock pattern enabled flag is being accessed for legacy reasons.
     */
    public static final String LEGACY_LOCK_PATTERN_ENABLED = "legacy_lock_pattern_enabled";

@@ -105,6 +105,12 @@ public class LockPatternUtils {
     */
    public static final int MIN_PATTERN_REGISTER_FAIL = MIN_LOCK_PATTERN_SIZE;

    public static final int CREDENTIAL_TYPE_NONE = -1;

    public static final int CREDENTIAL_TYPE_PATTERN = 1;

    public static final int CREDENTIAL_TYPE_PASSWORD = 2;

    @Deprecated
    public final static String LOCKOUT_PERMANENT_KEY = "lockscreen.lockedoutpermanently";
    public final static String LOCKOUT_ATTEMPT_DEADLINE = "lockscreen.lockoutattemptdeadline";
@@ -301,26 +307,11 @@ public class LockPatternUtils {
                null /* componentName */, userId);
    }

    /**
     * Check to see if a pattern matches the saved pattern.
     * If pattern matches, return an opaque attestation that the challenge
     * was verified.
     *
     * @param pattern The pattern to check.
     * @param challenge The challenge to verify against the pattern
     * @return the attestation that the challenge was verified, or null.
     */
    public byte[] verifyPattern(List<LockPatternView.Cell> pattern, long challenge, int userId)
    private byte[] verifyCredential(String credential, int type, long challenge, int userId)
            throws RequestThrottledException {
        throwIfCalledOnMainThread();
        try {
            VerifyCredentialResponse response =
                getLockSettings().verifyPattern(patternToString(pattern), challenge, userId);
            if (response == null) {
                // Shouldn't happen
                return null;
            }

            VerifyCredentialResponse response = getLockSettings().verifyCredential(credential,
                    type, challenge, userId);
            if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
                return response.getPayload();
            } else if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_RETRY) {
@@ -333,6 +324,41 @@ public class LockPatternUtils {
        }
    }

    private boolean checkCredential(String credential, int type, int userId,
            @Nullable CheckCredentialProgressCallback progressCallback)
            throws RequestThrottledException {
        try {
            VerifyCredentialResponse response = getLockSettings().checkCredential(credential, type,
                    userId, wrapCallback(progressCallback));

            if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
                return true;
            } else if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_RETRY) {
                throw new RequestThrottledException(response.getTimeout());
            } else {
                return false;
            }
        } catch (RemoteException re) {
            return false;
        }
    }

    /**
     * Check to see if a pattern matches the saved pattern.
     * If pattern matches, return an opaque attestation that the challenge
     * was verified.
     *
     * @param pattern The pattern to check.
     * @param challenge The challenge to verify against the pattern
     * @return the attestation that the challenge was verified, or null.
     */
    public byte[] verifyPattern(List<LockPatternView.Cell> pattern, long challenge, int userId)
            throws RequestThrottledException {
        throwIfCalledOnMainThread();
        return verifyCredential(patternToString(pattern), CREDENTIAL_TYPE_PATTERN, challenge,
                userId);
    }

    /**
     * Check to see if a pattern matches the saved pattern.  If no pattern exists,
     * always returns true.
@@ -354,21 +380,8 @@ public class LockPatternUtils {
            @Nullable CheckCredentialProgressCallback progressCallback)
            throws RequestThrottledException {
        throwIfCalledOnMainThread();
        try {
            VerifyCredentialResponse response =
                    getLockSettings().checkPattern(patternToString(pattern), userId,
                            wrapCallback(progressCallback));

            if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
                return true;
            } else if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_RETRY) {
                throw new RequestThrottledException(response.getTimeout());
            } else {
                return false;
            }
        } catch (RemoteException re) {
            return false;
        }
        return checkCredential(patternToString(pattern), CREDENTIAL_TYPE_PATTERN, userId,
                progressCallback);
    }

    /**
@@ -383,20 +396,7 @@ public class LockPatternUtils {
    public byte[] verifyPassword(String password, long challenge, int userId)
            throws RequestThrottledException {
        throwIfCalledOnMainThread();
        try {
            VerifyCredentialResponse response =
                    getLockSettings().verifyPassword(password, challenge, userId);

            if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
                return response.getPayload();
            } else if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_RETRY) {
                throw new RequestThrottledException(response.getTimeout());
            } else {
                return null;
            }
        } catch (RemoteException re) {
            return null;
        }
        return verifyCredential(password, CREDENTIAL_TYPE_PASSWORD, challenge, userId);
    }


@@ -414,7 +414,8 @@ public class LockPatternUtils {
        throwIfCalledOnMainThread();
        try {
            VerifyCredentialResponse response =
                    getLockSettings().verifyTiedProfileChallenge(password, isPattern, challenge,
                    getLockSettings().verifyTiedProfileChallenge(password,
                            isPattern ? CREDENTIAL_TYPE_PATTERN : CREDENTIAL_TYPE_PASSWORD, challenge,
                            userId);

            if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
@@ -449,19 +450,7 @@ public class LockPatternUtils {
            @Nullable CheckCredentialProgressCallback progressCallback)
            throws RequestThrottledException {
        throwIfCalledOnMainThread();
        try {
            VerifyCredentialResponse response =
                    getLockSettings().checkPassword(password, userId, wrapCallback(progressCallback));
            if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
                return true;
            } else if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_RETRY) {
                throw new RequestThrottledException(response.getTimeout());
            } else {
                return false;
            }
        } catch (RemoteException re) {
            return false;
        }
        return checkCredential(password, CREDENTIAL_TYPE_PASSWORD, userId, progressCallback);
    }

    /**
@@ -578,8 +567,7 @@ public class LockPatternUtils {
        setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, userHandle);

        try {
            getLockSettings().setLockPassword(null, null, userHandle);
            getLockSettings().setLockPattern(null, null, userHandle);
            getLockSettings().setLockCredential(null, CREDENTIAL_TYPE_NONE, null, userHandle);
        } catch (RemoteException e) {
            // well, we tried...
        }
@@ -643,8 +631,8 @@ public class LockPatternUtils {
            }

            setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING, userId);
            getLockSettings().setLockPattern(patternToString(pattern), savedPattern, userId);
            DevicePolicyManager dpm = getDevicePolicyManager();
            getLockSettings().setLockCredential(patternToString(pattern), CREDENTIAL_TYPE_PATTERN,
                    savedPattern, userId);

            // Update the device encryption password.
            if (userId == UserHandle.USER_SYSTEM
@@ -772,7 +760,8 @@ public class LockPatternUtils {

            final int computedQuality = PasswordMetrics.computeForPassword(password).quality;
            setLong(PASSWORD_TYPE_KEY, Math.max(quality, computedQuality), userHandle);
            getLockSettings().setLockPassword(password, savedPassword, userHandle);
            getLockSettings().setLockCredential(password, CREDENTIAL_TYPE_PASSWORD, savedPassword,
                    userHandle);

            // Update the device encryption password.
            if (userHandle == UserHandle.USER_SYSTEM
+162 −302

File changed.

Preview size limit exceeded, changes collapsed.

+77 −80
Original line number Diff line number Diff line
@@ -16,7 +16,7 @@

package com.android.server;

import com.android.internal.annotations.VisibleForTesting;
import static android.content.Context.USER_SERVICE;

import android.content.ContentValues;
import android.content.Context;
@@ -29,14 +29,15 @@ import android.os.UserManager;
import android.util.ArrayMap;
import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;

import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
import com.android.internal.widget.LockPatternUtils;

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;

import static android.content.Context.USER_SERVICE;

/**
 * Storage for the lock settings service.
 */
@@ -72,29 +73,48 @@ class LockSettingsStorage {
    private final Cache mCache = new Cache();
    private final Object mFileWriteLock = new Object();

    private SparseArray<Integer> mStoredCredentialType;

    static class CredentialHash {
        static final int TYPE_NONE = -1;
        static final int TYPE_PATTERN = 1;
        static final int TYPE_PASSWORD = 2;

    @VisibleForTesting
    public static class CredentialHash {
        static final int VERSION_LEGACY = 0;
        static final int VERSION_GATEKEEPER = 1;

        CredentialHash(byte[] hash, int version) {
        private CredentialHash(byte[] hash, int type, int version) {
            if (type != LockPatternUtils.CREDENTIAL_TYPE_NONE) {
                if (hash == null) {
                    throw new RuntimeException("Empty hash for CredentialHash");
                }
            } else /* type == LockPatternUtils.CREDENTIAL_TYPE_NONE */ {
                if (hash != null) {
                    throw new RuntimeException("None type CredentialHash should not have hash");
                }
            }
            this.hash = hash;
            this.type = type;
            this.version = version;
            this.isBaseZeroPattern = false;
        }

        CredentialHash(byte[] hash, boolean isBaseZeroPattern) {
        private CredentialHash(byte[] hash, boolean isBaseZeroPattern) {
            this.hash = hash;
            this.type = LockPatternUtils.CREDENTIAL_TYPE_PATTERN;
            this.version = VERSION_GATEKEEPER;
            this.isBaseZeroPattern = isBaseZeroPattern;
        }

        static CredentialHash create(byte[] hash, int type) {
            if (type == LockPatternUtils.CREDENTIAL_TYPE_NONE) {
                throw new RuntimeException("Bad type for CredentialHash");
            }
            return new CredentialHash(hash, type, VERSION_GATEKEEPER);
        }

        static CredentialHash createEmptyHash() {
            return new CredentialHash(null, LockPatternUtils.CREDENTIAL_TYPE_NONE,
                    VERSION_GATEKEEPER);
        }

        byte[] hash;
        int type;
        int version;
        boolean isBaseZeroPattern;
    }
@@ -102,7 +122,6 @@ class LockSettingsStorage {
    public LockSettingsStorage(Context context, Callback callback) {
        mContext = context;
        mOpenHelper = new DatabaseHelper(context, callback);
        mStoredCredentialType = new SparseArray<Integer>();
    }

    public void writeKeyValue(String key, String value, int userId) {
@@ -178,75 +197,62 @@ class LockSettingsStorage {
        }

        // Populate cache by reading the password and pattern files.
        readPasswordHash(userId);
        readPatternHash(userId);
    }

    public int getStoredCredentialType(int userId) {
        final Integer cachedStoredCredentialType = mStoredCredentialType.get(userId);
        if (cachedStoredCredentialType != null) {
            return cachedStoredCredentialType.intValue();
        }

        int storedCredentialType;
        CredentialHash pattern = readPatternHash(userId);
        if (pattern == null) {
            if (readPasswordHash(userId) != null) {
                storedCredentialType = CredentialHash.TYPE_PASSWORD;
            } else {
                storedCredentialType = CredentialHash.TYPE_NONE;
            }
        } else {
            CredentialHash password = readPasswordHash(userId);
            if (password != null) {
                // Both will never be GateKeeper
                if (password.version == CredentialHash.VERSION_GATEKEEPER) {
                    storedCredentialType = CredentialHash.TYPE_PASSWORD;
                } else {
                    storedCredentialType = CredentialHash.TYPE_PATTERN;
                }
            } else {
                storedCredentialType = CredentialHash.TYPE_PATTERN;
            }
        }
        mStoredCredentialType.put(userId, storedCredentialType);
        return storedCredentialType;
        readCredentialHash(userId);
    }


    public CredentialHash readPasswordHash(int userId) {
    private CredentialHash readPasswordHashIfExists(int userId) {
        byte[] stored = readFile(getLockPasswordFilename(userId));
        if (stored != null && stored.length > 0) {
            return new CredentialHash(stored, CredentialHash.VERSION_GATEKEEPER);
        if (!ArrayUtils.isEmpty(stored)) {
            return new CredentialHash(stored, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
                    CredentialHash.VERSION_GATEKEEPER);
        }

        stored = readFile(getLegacyLockPasswordFilename(userId));
        if (stored != null && stored.length > 0) {
            return new CredentialHash(stored, CredentialHash.VERSION_LEGACY);
        if (!ArrayUtils.isEmpty(stored)) {
            return new CredentialHash(stored, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
                    CredentialHash.VERSION_LEGACY);
        }

        return null;
    }

    public CredentialHash readPatternHash(int userId) {
    private CredentialHash readPatternHashIfExists(int userId) {
        byte[] stored = readFile(getLockPatternFilename(userId));
        if (stored != null && stored.length > 0) {
            return new CredentialHash(stored, CredentialHash.VERSION_GATEKEEPER);
        if (!ArrayUtils.isEmpty(stored)) {
            return new CredentialHash(stored, LockPatternUtils.CREDENTIAL_TYPE_PATTERN,
                    CredentialHash.VERSION_GATEKEEPER);
        }

        stored = readFile(getBaseZeroLockPatternFilename(userId));
        if (stored != null && stored.length > 0) {
        if (!ArrayUtils.isEmpty(stored)) {
            return new CredentialHash(stored, true);
        }

        stored = readFile(getLegacyLockPatternFilename(userId));
        if (stored != null && stored.length > 0) {
            return new CredentialHash(stored, CredentialHash.VERSION_LEGACY);
        if (!ArrayUtils.isEmpty(stored)) {
            return new CredentialHash(stored, LockPatternUtils.CREDENTIAL_TYPE_PATTERN,
                    CredentialHash.VERSION_LEGACY);
        }

        return null;
    }

    public CredentialHash readCredentialHash(int userId) {
        CredentialHash passwordHash = readPasswordHashIfExists(userId);
        CredentialHash patternHash = readPatternHashIfExists(userId);
        if (passwordHash != null && patternHash != null) {
            if (passwordHash.version == CredentialHash.VERSION_GATEKEEPER) {
                return passwordHash;
            } else {
                return patternHash;
            }
        } else if (passwordHash != null) {
            return passwordHash;
        } else if (patternHash != null) {
            return patternHash;
        } else {
            return CredentialHash.createEmptyHash();
        }
    }

    public void removeChildProfileLock(int userId) {
        if (DEBUG)
            Slog.e(TAG, "Remove child profile lock for user: " + userId);
@@ -355,26 +361,17 @@ class LockSettingsStorage {
        }
    }

    public void writePatternHash(byte[] hash, int userId) {
        mStoredCredentialType.put(userId, hash == null ? CredentialHash.TYPE_NONE
                : CredentialHash.TYPE_PATTERN);
        writeFile(getLockPatternFilename(userId), hash);
        clearPasswordHash(userId);
    }
    public void writeCredentialHash(CredentialHash hash, int userId) {
        byte[] patternHash = null;
        byte[] passwordHash = null;

    private void clearPatternHash(int userId) {
        writeFile(getLockPatternFilename(userId), null);
        if (hash.type == LockPatternUtils.CREDENTIAL_TYPE_PASSWORD) {
            passwordHash = hash.hash;
        } else if (hash.type == LockPatternUtils.CREDENTIAL_TYPE_PATTERN) {
            patternHash = hash.hash;
        }

    public void writePasswordHash(byte[] hash, int userId) {
        mStoredCredentialType.put(userId, hash == null ? CredentialHash.TYPE_NONE
                : CredentialHash.TYPE_PASSWORD);
        writeFile(getLockPasswordFilename(userId), hash);
        clearPatternHash(userId);
    }

    private void clearPasswordHash(int userId) {
        writeFile(getLockPasswordFilename(userId), null);
        writeFile(getLockPasswordFilename(userId), passwordHash);
        writeFile(getLockPatternFilename(userId), patternHash);
    }

    @VisibleForTesting
+110 −84

File changed.

Preview size limit exceeded, changes collapsed.