// Copyright (c) 2011, Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package net.tawacentral.roger.secrets;
import android.graphics.Color;
/**
* This enum contains a static method that generates password strength scores
* for string passwords.
*
* The strength method implements the Truong3 Password Strength Algorithm, which
* determines if the password contains:
* . at least 6 characters
* . at least one upper and one lower case Latin alphabet character
* . at least one numerical character
* . at least one special character
*
* This enum provides a couple methods related to UI for retrieving a
* descriptive String and Color associated with the strength.
*
* @author stevet
*/
enum PasswordStrength {
WEAK(R.string.password_strength_weak, Color.RED),
MEDIUM(R.string.password_strength_medium,
Color.argb(255, 220, 185, 0)), // Orange
STRONG(R.string.password_strength_strong, Color.YELLOW),
VERY_STRONG(R.string.password_strength_very_strong,
Color.argb(255, 170, 255, 0)), // Chartreuse
CRAZY_STRONG(R.string.password_strength_crazy_strong, Color.GREEN);
PasswordStrength(int resId, int color) {
this.resId = resId;
this.color = color;
}
/**
* Returns the text for this password strength.
*/
CharSequence getText(android.content.Context ctx) {
return ctx.getText(resId);
}
/**
* Returns the color associated with this password strength.
*/
int getColor() {
return color;
}
/**
* Static helper for calculating a password strength from scratch.
* Runtime: O(N).
*/
static PasswordStrength calculateStrength(String password) {
int currentScore = 0;
boolean sawUpper = false;
boolean sawLower = false;
boolean sawDigit = false;
boolean sawSpecial = false;
// The first time the length passes 6, we increment the score.
if (password.length() > 6)
currentScore += 1;
// Do this as efficiently as possible.
for (int i = 0; i < password.length(); i++) {
char c = password.charAt(i);
if (!sawSpecial && !Character.isLetterOrDigit(c)) {
currentScore += 1;
sawSpecial = true;
} else {
if (!sawDigit && Character.isDigit(c)) {
currentScore += 1;
sawDigit = true;
} else {
if (!sawUpper || !sawLower) {
if (Character.isUpperCase(c))
sawUpper = true;
else
sawLower = true;
if (sawUpper && sawLower)
currentScore += 1;
}
}
}
}
switch (currentScore) {
case 0: return WEAK;
case 1: return MEDIUM;
case 2: return STRONG;
case 3: return VERY_STRONG;
case 4: return CRAZY_STRONG;
default: // Fall through.
}
// This shouldn't happen with this particular algorithm, but if it does,
// that means we have a score over 4, so that's good, right?
// TODO(stevet): assert instead.
return CRAZY_STRONG;
}
int resId;
int color;
}