Simpler password strength estimation.

parent 1918346a
......@@ -6,9 +6,9 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
public interface PasswordStrengthEstimator {
float NONE = 0;
float WEAK = 0.4f;
float QUITE_WEAK = 0.6f;
float QUITE_STRONG = 0.8f;
float WEAK = 0.25f;
float QUITE_WEAK = 0.5f;
float QUITE_STRONG = 0.75f;
float STRONG = 1;
/**
......
......@@ -11,31 +11,14 @@ import javax.annotation.concurrent.Immutable;
@NotNullByDefault
class PasswordStrengthEstimatorImpl implements PasswordStrengthEstimator {
private static final int LOWER = 26;
private static final int UPPER = 26;
private static final int DIGIT = 10;
private static final int OTHER = 10;
private static final double STRONG = Math.log(Math.pow(LOWER + UPPER +
DIGIT + OTHER, 10));
// The minimum number of unique characters in a strong password
private static final int STRONG_UNIQUE_CHARS = 12;
@Override
public float estimateStrength(String password) {
HashSet<Character> unique = new HashSet<Character>();
int length = password.length();
for (int i = 0; i < length; i++) unique.add(password.charAt(i));
boolean lower = false, upper = false, digit = false, other = false;
for (char c : unique) {
if (Character.isLowerCase(c)) lower = true;
else if (Character.isUpperCase(c)) upper = true;
else if (Character.isDigit(c)) digit = true;
else other = true;
}
int alphabetSize = 0;
if (lower) alphabetSize += LOWER;
if (upper) alphabetSize += UPPER;
if (digit) alphabetSize += DIGIT;
if (other) alphabetSize += OTHER;
double score = Math.log(Math.pow(alphabetSize, unique.size()));
return Math.min(1, (float) (score / STRONG));
return Math.min(1, (float) unique.size() / STRONG_UNIQUE_CHARS);
}
}
......@@ -4,6 +4,7 @@ import org.briarproject.bramble.api.crypto.PasswordStrengthEstimator;
import org.briarproject.bramble.test.BrambleTestCase;
import org.junit.Test;
import static org.briarproject.bramble.api.crypto.PasswordStrengthEstimator.NONE;
import static org.briarproject.bramble.api.crypto.PasswordStrengthEstimator.QUITE_STRONG;
import static org.junit.Assert.assertTrue;
......@@ -12,7 +13,7 @@ public class PasswordStrengthEstimatorImplTest extends BrambleTestCase {
@Test
public void testWeakPasswords() {
PasswordStrengthEstimator e = new PasswordStrengthEstimatorImpl();
assertTrue(e.estimateStrength("") < QUITE_STRONG);
assertTrue(e.estimateStrength("") == NONE);
assertTrue(e.estimateStrength("password") < QUITE_STRONG);
assertTrue(e.estimateStrength("letmein") < QUITE_STRONG);
assertTrue(e.estimateStrength("123456") < QUITE_STRONG);
......
......@@ -25,7 +25,7 @@ import javax.inject.Inject;
import static android.view.View.INVISIBLE;
import static android.view.View.VISIBLE;
import static org.briarproject.bramble.api.crypto.PasswordStrengthEstimator.WEAK;
import static org.briarproject.bramble.api.crypto.PasswordStrengthEstimator.QUITE_WEAK;
public class ChangePasswordActivity extends BaseActivity
implements OnClickListener, OnEditorActionListener {
......@@ -109,13 +109,13 @@ public class ChangePasswordActivity extends BaseActivity
strengthMeter.setStrength(strength);
UiUtils.setError(newPasswordEntryWrapper,
getString(R.string.password_too_weak),
firstPassword.length() > 0 && strength < WEAK);
firstPassword.length() > 0 && strength < QUITE_WEAK);
UiUtils.setError(newPasswordConfirmationWrapper,
getString(R.string.passwords_do_not_match),
secondPassword.length() > 0 && !passwordsMatch);
changePasswordButton.setEnabled(
!currentPassword.getText().toString().isEmpty() &&
passwordsMatch && strength >= WEAK);
passwordsMatch && strength >= QUITE_WEAK);
}
@Override
......
......@@ -28,7 +28,7 @@ import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static android.view.View.GONE;
import static android.view.View.INVISIBLE;
import static android.view.View.VISIBLE;
import static org.briarproject.bramble.api.crypto.PasswordStrengthEstimator.WEAK;
import static org.briarproject.bramble.api.crypto.PasswordStrengthEstimator.QUITE_WEAK;
import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH;
public class SetupActivity extends BaseActivity implements OnClickListener,
......@@ -115,13 +115,13 @@ public class SetupActivity extends BaseActivity implements OnClickListener,
nicknameLength > MAX_AUTHOR_NAME_LENGTH);
UiUtils.setError(passwordEntryWrapper,
getString(R.string.password_too_weak),
firstPassword.length() > 0 && strength < WEAK);
firstPassword.length() > 0 && strength < QUITE_WEAK);
UiUtils.setError(passwordConfirmationWrapper,
getString(R.string.passwords_do_not_match),
secondPassword.length() > 0 && !passwordsMatch);
createAccountButton.setEnabled(nicknameLength > 0
&& nicknameLength <= MAX_AUTHOR_NAME_LENGTH
&& passwordsMatch && strength >= WEAK);
&& passwordsMatch && strength >= QUITE_WEAK);
}
@Override
......
......@@ -193,7 +193,7 @@ public class ChangePasswordActivityTest {
// Mock answers for UI testing only
when(mockedController.estimatePasswordStrength("strong")).thenReturn(
STRONG);
when(mockedController.estimatePasswordStrength("qstring")).thenReturn(
when(mockedController.estimatePasswordStrength("qstrong")).thenReturn(
QUITE_STRONG);
when(mockedController.estimatePasswordStrength("qweak")).thenReturn(
QUITE_WEAK);
......@@ -205,9 +205,9 @@ public class ChangePasswordActivityTest {
testStrengthMeter("strong", STRONG, StrengthMeter.GREEN);
Mockito.verify(mockedController, Mockito.times(1))
.estimatePasswordStrength(eq("strong"));
testStrengthMeter("qstring", QUITE_STRONG, StrengthMeter.LIME);
testStrengthMeter("qstrong", QUITE_STRONG, StrengthMeter.LIME);
Mockito.verify(mockedController, Mockito.times(1))
.estimatePasswordStrength(eq("qstring"));
.estimatePasswordStrength(eq("qstrong"));
testStrengthMeter("qweak", QUITE_WEAK, StrengthMeter.YELLOW);
Mockito.verify(mockedController, Mockito.times(1))
.estimatePasswordStrength(eq("qweak"));
......
......@@ -196,7 +196,7 @@ public class SetupActivityTest {
// Mock answers for UI testing only
when(mockedController.estimatePasswordStrength("strong")).thenReturn(
STRONG);
when(mockedController.estimatePasswordStrength("qstring")).thenReturn(
when(mockedController.estimatePasswordStrength("qstrong")).thenReturn(
QUITE_STRONG);
when(mockedController.estimatePasswordStrength("qweak")).thenReturn(
QUITE_WEAK);
......@@ -208,9 +208,9 @@ public class SetupActivityTest {
testStrengthMeter("strong", STRONG, StrengthMeter.GREEN);
Mockito.verify(mockedController, Mockito.times(1))
.estimatePasswordStrength(eq("strong"));
testStrengthMeter("qstring", QUITE_STRONG, StrengthMeter.LIME);
testStrengthMeter("qstrong", QUITE_STRONG, StrengthMeter.LIME);
Mockito.verify(mockedController, Mockito.times(1))
.estimatePasswordStrength(eq("qstring"));
.estimatePasswordStrength(eq("qstrong"));
testStrengthMeter("qweak", QUITE_WEAK, StrengthMeter.YELLOW);
Mockito.verify(mockedController, Mockito.times(1))
.estimatePasswordStrength(eq("qweak"));
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment