Skip to content

Commit

Permalink
Prevent factory reset for short passwords in CryptKeeper
Browse files Browse the repository at this point in the history
Since patterns and passwords can't be shorter than 4
elements, we shouldn't count them against attempts to unlock
the device.  If we do, we risk resetting the device
due to stray input.

Bug: 18211475
Bug: 18273380

Change-Id: Ib329cd3383471483cda68bfac4278b17d0c09c57

Conflicts:
	src/com/android/settings/CryptKeeper.java

Conflicts:
	src/com/android/settings/CryptKeeper.java
  • Loading branch information
ciphergoth authored and Alberto97 committed Dec 3, 2014
1 parent 07be3ff commit b6724a8
Showing 1 changed file with 69 additions and 38 deletions.
107 changes: 69 additions & 38 deletions src/com/android/settings/CryptKeeper.java
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,17 @@ public class CryptKeeper extends Activity implements TextView.OnEditorActionList
// how long we wait to clear a right pattern
private static final int RIGHT_PATTERN_CLEAR_TIMEOUT_MS = 500;

// When the user enters a short pin/password, run this to show an error,
// but don't count it against attempts.
private final Runnable mFakeUnlockAttemptRunnable = new Runnable() {
public void run() {
handleBadAttempt(1 /* failedAttempt */);
}
};

// TODO: this should be tuned to match minimum decryption timeout
private static final int FAKE_ATTEMPT_DELAY = 1000;

private Runnable mClearPatternRunnable = new Runnable() {
public void run() {
mLockPatternView.clearPattern();
Expand Down Expand Up @@ -200,43 +211,47 @@ protected void onPostExecute(Integer failedAttempts) {
showFactoryReset(true);
return;
} else {
// Wrong entry. Handle pattern case.
if (mLockPatternView != null) {
mLockPatternView.setDisplayMode(DisplayMode.Wrong);
mLockPatternView.removeCallbacks(mClearPatternRunnable);
mLockPatternView.postDelayed(mClearPatternRunnable, WRONG_PATTERN_CLEAR_TIMEOUT_MS);
}
if ((failedAttempts % COOL_DOWN_ATTEMPTS) == 0) {
mCooldown = COOL_DOWN_INTERVAL;
cooldown();
} else {
final TextView status = (TextView) findViewById(R.id.status);
handleBadAttempt(failedAttempts);
}
}
}

int remainingAttempts = MAX_FAILED_ATTEMPTS - failedAttempts;
if (remainingAttempts < COOL_DOWN_ATTEMPTS) {
CharSequence warningTemplate = getText(R.string.crypt_keeper_warn_wipe);
CharSequence warning = TextUtils.expandTemplate(warningTemplate,
Integer.toString(remainingAttempts));
status.setText(warning);
} else {
status.setText(R.string.try_again);
}
private void handleBadAttempt(Integer failedAttempts) {
// Wrong entry. Handle pattern case.
if (mLockPatternView != null) {
mLockPatternView.setDisplayMode(DisplayMode.Wrong);
mLockPatternView.removeCallbacks(mClearPatternRunnable);
mLockPatternView.postDelayed(mClearPatternRunnable, WRONG_PATTERN_CLEAR_TIMEOUT_MS);
}
if ((failedAttempts % COOL_DOWN_ATTEMPTS) == 0) {
mCooldown = COOL_DOWN_INTERVAL;
cooldown();
} else {
final TextView status = (TextView) findViewById(R.id.status);

int remainingAttempts = MAX_FAILED_ATTEMPTS - failedAttempts;
if (remainingAttempts < COOL_DOWN_ATTEMPTS) {
CharSequence warningTemplate = getText(R.string.crypt_keeper_warn_wipe);
CharSequence warning = TextUtils.expandTemplate(warningTemplate,
Integer.toString(remainingAttempts));
status.setText(warning);
} else {
status.setText(R.string.try_again);
}

if (mLockPatternView != null) {
mLockPatternView.setDisplayMode(DisplayMode.Wrong);
}
// Reenable the password entry
if (mPasswordEntry != null) {
mPasswordEntry.setEnabled(true);
final InputMethodManager imm = (InputMethodManager) getSystemService(
Context.INPUT_METHOD_SERVICE);
imm.showSoftInput(mPasswordEntry, 0);
setBackFunctionality(true);
}
if (mLockPatternView != null) {
mLockPatternView.setEnabled(true);
}
}
if (mLockPatternView != null) {
mLockPatternView.setDisplayMode(DisplayMode.Wrong);
}
// Reenable the password entry
if (mPasswordEntry != null) {
mPasswordEntry.setEnabled(true);
final InputMethodManager imm = (InputMethodManager) getSystemService(
Context.INPUT_METHOD_SERVICE);
imm.showSoftInput(mPasswordEntry, 0);
setBackFunctionality(true);
}
if (mLockPatternView != null) {
mLockPatternView.setEnabled(true);
}
}
}
Expand Down Expand Up @@ -307,6 +322,8 @@ public void handleMessage(Message msg) {
| StatusBarManager.DISABLE_SEARCH
| StatusBarManager.DISABLE_RECENT;

protected static final int MIN_LENGTH_BEFORE_REPORT = LockPatternUtils.MIN_LOCK_PATTERN_SIZE;

/** @return whether or not this Activity was started for debugging the UI only. */
private boolean isDebugView() {
return getIntent().hasExtra(EXTRA_FORCE_VIEW);
Expand Down Expand Up @@ -679,6 +696,10 @@ private final void setBackFunctionality(boolean isEnabled) {
}
}

private void fakeUnlockAttempt(View postingView) {
postingView.postDelayed(mFakeUnlockAttemptRunnable, FAKE_ATTEMPT_DELAY);
}

protected LockPatternView.OnPatternListener mChooseNewLockPatternListener =
new LockPatternView.OnPatternListener() {

Expand All @@ -694,7 +715,12 @@ public void onPatternCleared() {
@Override
public void onPatternDetected(List<LockPatternView.Cell> pattern) {
mLockPatternView.setEnabled(false);
new DecryptTask().execute(LockPatternUtils.patternToString(pattern));
if (pattern.size() >= MIN_LENGTH_BEFORE_REPORT) {
new DecryptTask().execute(LockPatternUtils.patternToString(pattern));
} else {
// Allow user to make as many of these as they want.
fakeUnlockAttempt(mLockPatternView);
}
}

@Override
Expand Down Expand Up @@ -851,8 +877,13 @@ public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
mPasswordEntry.setEnabled(false);
setBackFunctionality(false);

Log.d(TAG, "Attempting to send command to decrypt");
new DecryptTask().execute(password);
if (password.length() >= LockPatternUtils.MIN_LOCK_PATTERN_SIZE) {
Log.d(TAG, "Attempting to send command to decrypt");
new DecryptTask().execute(password);
} else {
// Allow user to make as many of these as they want.
fakeUnlockAttempt(mPasswordEntry);
}

return true;
}
Expand Down

0 comments on commit b6724a8

Please sign in to comment.