diff options
author | Jim Miller <jaggies@google.com> | 2014-01-31 17:08:37 -0800 |
---|---|---|
committer | Jim Miller <jaggies@google.com> | 2014-07-10 01:54:49 +0000 |
commit | 85516d028b2dcc7ebc09f4a68085836aa26191d5 (patch) | |
tree | a36227d94fd559b29cdb7ed6240324808e3c7d78 | |
parent | 9f6414d0e6348e2f9ebbaede0424608220cba24c (diff) | |
download | frameworks_base-85516d028b2dcc7ebc09f4a68085836aa26191d5.zip frameworks_base-85516d028b2dcc7ebc09f4a68085836aa26191d5.tar.gz frameworks_base-85516d028b2dcc7ebc09f4a68085836aa26191d5.tar.bz2 |
Add new "pin complex" type to supported keyguard PINs
This adds a feature to allow DevicePolicyAdmins to prevent using
simple PINs, which are defined as those containing more than 3
repeated values. Examples include '1234', '2468', '1111', '9876', etc.
Bug 12081139
Change-Id: I4ebe1c76a48087dcd7c878e9bd79a4e3ee2a27fe
5 files changed, 96 insertions, 9 deletions
diff --git a/api/current.txt b/api/current.txt index 29ec56b..60a18d8 100644 --- a/api/current.txt +++ b/api/current.txt @@ -5372,6 +5372,7 @@ package android.app.admin { field public static final int PASSWORD_QUALITY_BIOMETRIC_WEAK = 32768; // 0x8000 field public static final int PASSWORD_QUALITY_COMPLEX = 393216; // 0x60000 field public static final int PASSWORD_QUALITY_NUMERIC = 131072; // 0x20000 + field public static final int PASSWORD_QUALITY_NUMERIC_COMPLEX = 196608; // 0x30000 field public static final int PASSWORD_QUALITY_SOMETHING = 65536; // 0x10000 field public static final int PASSWORD_QUALITY_UNSPECIFIED = 0; // 0x0 field public static final java.lang.String PROVISIONING_NFC_MIME_TYPE = "application/com.android.managedprovisioning"; diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 49b1d10..2feec1b 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -509,6 +509,14 @@ public class DevicePolicyManager { /** * Constant for {@link #setPasswordQuality}: the user must have entered a + * password containing at least numeric characters with no repeating (4444) + * or ordered (1234, 4321, 2468) sequences. Note that quality + * constants are ordered so that higher values are more restrictive. + */ + public static final int PASSWORD_QUALITY_NUMERIC_COMPLEX = 0x30000; + + /** + * Constant for {@link #setPasswordQuality}: the user must have entered a * password containing at least alphabetic (or other symbol) characters. * Note that quality constants are ordered so that higher values are more * restrictive. @@ -556,8 +564,9 @@ public class DevicePolicyManager { * @param admin Which {@link DeviceAdminReceiver} this request is associated with. * @param quality The new desired quality. One of * {@link #PASSWORD_QUALITY_UNSPECIFIED}, {@link #PASSWORD_QUALITY_SOMETHING}, - * {@link #PASSWORD_QUALITY_NUMERIC}, {@link #PASSWORD_QUALITY_ALPHABETIC}, - * {@link #PASSWORD_QUALITY_ALPHANUMERIC} or {@link #PASSWORD_QUALITY_COMPLEX}. + * {@link #PASSWORD_QUALITY_NUMERIC}, {@link #PASSWORD_QUALITY_NUMERIC_COMPLEX}, + * {@link #PASSWORD_QUALITY_ALPHABETIC}, {@link #PASSWORD_QUALITY_ALPHANUMERIC} + * or {@link #PASSWORD_QUALITY_COMPLEX}. */ public void setPasswordQuality(ComponentName admin, int quality) { if (mService != null) { @@ -600,9 +609,9 @@ public class DevicePolicyManager { * take place immediately. To prompt the user for a new password, use * {@link #ACTION_SET_NEW_PASSWORD} after setting this value. This * constraint is only imposed if the administrator has also requested either - * {@link #PASSWORD_QUALITY_NUMERIC}, {@link #PASSWORD_QUALITY_ALPHABETIC} - * {@link #PASSWORD_QUALITY_ALPHANUMERIC}, or {@link #PASSWORD_QUALITY_COMPLEX} - * with {@link #setPasswordQuality}. + * {@link #PASSWORD_QUALITY_NUMERIC}, {@link #PASSWORD_QUALITY_NUMERIC_COMPLEX}, + * {@link #PASSWORD_QUALITY_ALPHABETIC}, {@link #PASSWORD_QUALITY_ALPHANUMERIC}, + * or {@link #PASSWORD_QUALITY_COMPLEX} with {@link #setPasswordQuality}. * * <p>The calling device admin must have requested * {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD} to be able to call @@ -1008,9 +1017,9 @@ public class DevicePolicyManager { * the change does not take place immediately. To prompt the user for a new * password, use {@link #ACTION_SET_NEW_PASSWORD} after setting this value. * This constraint is only imposed if the administrator has also requested - * either {@link #PASSWORD_QUALITY_NUMERIC}, - * {@link #PASSWORD_QUALITY_ALPHABETIC}, or - * {@link #PASSWORD_QUALITY_ALPHANUMERIC} with {@link #setPasswordQuality}. + * either {@link #PASSWORD_QUALITY_NUMERIC}, {@link #PASSWORD_QUALITY_NUMERIC_COMPLEX} + * {@link #PASSWORD_QUALITY_ALPHABETIC}, or {@link #PASSWORD_QUALITY_ALPHANUMERIC} + * with {@link #setPasswordQuality}. * * <p> * The calling device admin must have requested diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java index 5409de7..f40b84c 100644 --- a/core/java/com/android/internal/widget/LockPatternUtils.java +++ b/core/java/com/android/internal/widget/LockPatternUtils.java @@ -150,6 +150,10 @@ public class LockPatternUtils { private static final String ENABLED_TRUST_AGENTS = "lockscreen.enabledtrustagents"; + // Maximum allowed number of repeated or ordered characters in a sequence before we'll + // consider it a complex PIN/password. + public static final int MAX_ALLOWED_SEQUENCE = 3; + private final Context mContext; private final ContentResolver mContentResolver; private DevicePolicyManager mDevicePolicyManager; @@ -441,6 +445,11 @@ public class LockPatternUtils { activePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_NUMERIC; } break; + case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX: + if (isLockPasswordEnabled()) { + activePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX; + } + break; case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC: if (isLockPasswordEnabled()) { activePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC; @@ -625,11 +634,74 @@ public class LockPatternUtils { return DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC; } if (hasDigit) { - return DevicePolicyManager.PASSWORD_QUALITY_NUMERIC; + return maxLengthSequence(password) > MAX_ALLOWED_SEQUENCE + ? DevicePolicyManager.PASSWORD_QUALITY_NUMERIC + : DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX; } return DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED; } + private static int categoryChar(char c) { + if ('a' <= c && c <= 'z') return 0; + if ('A' <= c && c <= 'Z') return 1; + if ('0' <= c && c <= '9') return 2; + return 3; + } + + private static int maxDiffCategory(int category) { + if (category == 0 || category == 1) return 1; + else if (category == 2) return 10; + return 0; + } + + /* + * Returns the maximum length of a sequential characters. A sequence is defined as + * monotonically increasing characters with a constant interval or the same character repeated. + * + * For example: + * maxLengthSequence("1234") == 4 + * maxLengthSequence("1234abc") == 4 + * maxLengthSequence("aabc") == 3 + * maxLengthSequence("qwertyuio") == 1 + * maxLengthSequence("@ABC") == 3 + * maxLengthSequence(";;;;") == 4 (anything that repeats) + * maxLengthSequence(":;<=>") == 1 (ordered, but not composed of alphas or digits) + * + * @param string the pass + * @return the number of sequential letters or digits + */ + public static int maxLengthSequence(String string) { + if (string.length() == 0) return 0; + char previousChar = string.charAt(0); + int category = categoryChar(previousChar); //current category of the sequence + int diff = 0; //difference between two consecutive characters + boolean hasDiff = false; //if we are currently targeting a sequence + int maxLength = 0; //maximum length of a sequence already found + int startSequence = 0; //where the current sequence started + for (int current = 1; current < string.length(); current++) { + char currentChar = string.charAt(current); + int categoryCurrent = categoryChar(currentChar); + int currentDiff = (int) currentChar - (int) previousChar; + if (categoryCurrent != category || Math.abs(currentDiff) > maxDiffCategory(category)) { + maxLength = Math.max(maxLength, current - startSequence); + startSequence = current; + hasDiff = false; + category = categoryCurrent; + } + else { + if(hasDiff && currentDiff != diff) { + maxLength = Math.max(maxLength, current - startSequence); + startSequence = current - 1; + } + diff = currentDiff; + hasDiff = true; + } + previousChar = currentChar; + } + maxLength = Math.max(maxLength, string.length() - startSequence); + return maxLength; + } + /** Update the encryption password if it is enabled **/ private void updateEncryptionPassword(int type, String password) { DevicePolicyManager dpm = getDevicePolicyManager(); @@ -926,10 +998,12 @@ public class LockPatternUtils { long backupMode = getLong(PASSWORD_TYPE_ALTERNATE_KEY, 0); final boolean passwordEnabled = mode == DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC || mode == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC + || mode == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX || mode == DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC || mode == DevicePolicyManager.PASSWORD_QUALITY_COMPLEX; final boolean backupEnabled = backupMode == DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC || backupMode == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC + || backupMode == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX || backupMode == DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC || backupMode == DevicePolicyManager.PASSWORD_QUALITY_COMPLEX; @@ -1307,6 +1381,7 @@ public class LockPatternUtils { long mode = getKeyguardStoredPasswordQuality(); final boolean isPattern = mode == DevicePolicyManager.PASSWORD_QUALITY_SOMETHING; final boolean isPassword = mode == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC + || mode == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX || mode == DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC || mode == DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC || mode == DevicePolicyManager.PASSWORD_QUALITY_COMPLEX; diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityModel.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityModel.java index 5ef41c9..3166ad4 100644 --- a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityModel.java +++ b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityModel.java @@ -87,6 +87,7 @@ public class KeyguardSecurityModel { final int security = mLockPatternUtils.getKeyguardStoredPasswordQuality(); switch (security) { case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC: + case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX: mode = mLockPatternUtils.isLockPasswordEnabled() ? SecurityMode.PIN : SecurityMode.None; break; diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index e956dfb..61f09f6 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -1190,6 +1190,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { case DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK: case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING: case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC: + case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX: case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC: case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC: case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX: |