mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-16 20:59:54 +01:00
Simpler password strength estimation.
This commit is contained in:
@@ -6,9 +6,9 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
|||||||
public interface PasswordStrengthEstimator {
|
public interface PasswordStrengthEstimator {
|
||||||
|
|
||||||
float NONE = 0;
|
float NONE = 0;
|
||||||
float WEAK = 0.4f;
|
float WEAK = 0.25f;
|
||||||
float QUITE_WEAK = 0.6f;
|
float QUITE_WEAK = 0.5f;
|
||||||
float QUITE_STRONG = 0.8f;
|
float QUITE_STRONG = 0.75f;
|
||||||
float STRONG = 1;
|
float STRONG = 1;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -11,31 +11,14 @@ import javax.annotation.concurrent.Immutable;
|
|||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
class PasswordStrengthEstimatorImpl implements PasswordStrengthEstimator {
|
class PasswordStrengthEstimatorImpl implements PasswordStrengthEstimator {
|
||||||
|
|
||||||
private static final int LOWER = 26;
|
// The minimum number of unique characters in a strong password
|
||||||
private static final int UPPER = 26;
|
private static final int STRONG_UNIQUE_CHARS = 12;
|
||||||
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));
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public float estimateStrength(String password) {
|
public float estimateStrength(String password) {
|
||||||
HashSet<Character> unique = new HashSet<Character>();
|
HashSet<Character> unique = new HashSet<Character>();
|
||||||
int length = password.length();
|
int length = password.length();
|
||||||
for (int i = 0; i < length; i++) unique.add(password.charAt(i));
|
for (int i = 0; i < length; i++) unique.add(password.charAt(i));
|
||||||
boolean lower = false, upper = false, digit = false, other = false;
|
return Math.min(1, (float) unique.size() / STRONG_UNIQUE_CHARS);
|
||||||
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));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import org.briarproject.bramble.api.crypto.PasswordStrengthEstimator;
|
|||||||
import org.briarproject.bramble.test.BrambleTestCase;
|
import org.briarproject.bramble.test.BrambleTestCase;
|
||||||
import org.junit.Test;
|
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.briarproject.bramble.api.crypto.PasswordStrengthEstimator.QUITE_STRONG;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
@@ -12,7 +13,7 @@ public class PasswordStrengthEstimatorImplTest extends BrambleTestCase {
|
|||||||
@Test
|
@Test
|
||||||
public void testWeakPasswords() {
|
public void testWeakPasswords() {
|
||||||
PasswordStrengthEstimator e = new PasswordStrengthEstimatorImpl();
|
PasswordStrengthEstimator e = new PasswordStrengthEstimatorImpl();
|
||||||
assertTrue(e.estimateStrength("") < QUITE_STRONG);
|
assertTrue(e.estimateStrength("") == NONE);
|
||||||
assertTrue(e.estimateStrength("password") < QUITE_STRONG);
|
assertTrue(e.estimateStrength("password") < QUITE_STRONG);
|
||||||
assertTrue(e.estimateStrength("letmein") < QUITE_STRONG);
|
assertTrue(e.estimateStrength("letmein") < QUITE_STRONG);
|
||||||
assertTrue(e.estimateStrength("123456") < 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.INVISIBLE;
|
||||||
import static android.view.View.VISIBLE;
|
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
|
public class ChangePasswordActivity extends BaseActivity
|
||||||
implements OnClickListener, OnEditorActionListener {
|
implements OnClickListener, OnEditorActionListener {
|
||||||
@@ -109,13 +109,13 @@ public class ChangePasswordActivity extends BaseActivity
|
|||||||
strengthMeter.setStrength(strength);
|
strengthMeter.setStrength(strength);
|
||||||
UiUtils.setError(newPasswordEntryWrapper,
|
UiUtils.setError(newPasswordEntryWrapper,
|
||||||
getString(R.string.password_too_weak),
|
getString(R.string.password_too_weak),
|
||||||
firstPassword.length() > 0 && strength < WEAK);
|
firstPassword.length() > 0 && strength < QUITE_WEAK);
|
||||||
UiUtils.setError(newPasswordConfirmationWrapper,
|
UiUtils.setError(newPasswordConfirmationWrapper,
|
||||||
getString(R.string.passwords_do_not_match),
|
getString(R.string.passwords_do_not_match),
|
||||||
secondPassword.length() > 0 && !passwordsMatch);
|
secondPassword.length() > 0 && !passwordsMatch);
|
||||||
changePasswordButton.setEnabled(
|
changePasswordButton.setEnabled(
|
||||||
!currentPassword.getText().toString().isEmpty() &&
|
!currentPassword.getText().toString().isEmpty() &&
|
||||||
passwordsMatch && strength >= WEAK);
|
passwordsMatch && strength >= QUITE_WEAK);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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.GONE;
|
||||||
import static android.view.View.INVISIBLE;
|
import static android.view.View.INVISIBLE;
|
||||||
import static android.view.View.VISIBLE;
|
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;
|
import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH;
|
||||||
|
|
||||||
public class SetupActivity extends BaseActivity implements OnClickListener,
|
public class SetupActivity extends BaseActivity implements OnClickListener,
|
||||||
@@ -115,13 +115,13 @@ public class SetupActivity extends BaseActivity implements OnClickListener,
|
|||||||
nicknameLength > MAX_AUTHOR_NAME_LENGTH);
|
nicknameLength > MAX_AUTHOR_NAME_LENGTH);
|
||||||
UiUtils.setError(passwordEntryWrapper,
|
UiUtils.setError(passwordEntryWrapper,
|
||||||
getString(R.string.password_too_weak),
|
getString(R.string.password_too_weak),
|
||||||
firstPassword.length() > 0 && strength < WEAK);
|
firstPassword.length() > 0 && strength < QUITE_WEAK);
|
||||||
UiUtils.setError(passwordConfirmationWrapper,
|
UiUtils.setError(passwordConfirmationWrapper,
|
||||||
getString(R.string.passwords_do_not_match),
|
getString(R.string.passwords_do_not_match),
|
||||||
secondPassword.length() > 0 && !passwordsMatch);
|
secondPassword.length() > 0 && !passwordsMatch);
|
||||||
createAccountButton.setEnabled(nicknameLength > 0
|
createAccountButton.setEnabled(nicknameLength > 0
|
||||||
&& nicknameLength <= MAX_AUTHOR_NAME_LENGTH
|
&& nicknameLength <= MAX_AUTHOR_NAME_LENGTH
|
||||||
&& passwordsMatch && strength >= WEAK);
|
&& passwordsMatch && strength >= QUITE_WEAK);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -193,7 +193,7 @@ public class ChangePasswordActivityTest {
|
|||||||
// Mock answers for UI testing only
|
// Mock answers for UI testing only
|
||||||
when(mockedController.estimatePasswordStrength("strong")).thenReturn(
|
when(mockedController.estimatePasswordStrength("strong")).thenReturn(
|
||||||
STRONG);
|
STRONG);
|
||||||
when(mockedController.estimatePasswordStrength("qstring")).thenReturn(
|
when(mockedController.estimatePasswordStrength("qstrong")).thenReturn(
|
||||||
QUITE_STRONG);
|
QUITE_STRONG);
|
||||||
when(mockedController.estimatePasswordStrength("qweak")).thenReturn(
|
when(mockedController.estimatePasswordStrength("qweak")).thenReturn(
|
||||||
QUITE_WEAK);
|
QUITE_WEAK);
|
||||||
@@ -205,9 +205,9 @@ public class ChangePasswordActivityTest {
|
|||||||
testStrengthMeter("strong", STRONG, StrengthMeter.GREEN);
|
testStrengthMeter("strong", STRONG, StrengthMeter.GREEN);
|
||||||
Mockito.verify(mockedController, Mockito.times(1))
|
Mockito.verify(mockedController, Mockito.times(1))
|
||||||
.estimatePasswordStrength(eq("strong"));
|
.estimatePasswordStrength(eq("strong"));
|
||||||
testStrengthMeter("qstring", QUITE_STRONG, StrengthMeter.LIME);
|
testStrengthMeter("qstrong", QUITE_STRONG, StrengthMeter.LIME);
|
||||||
Mockito.verify(mockedController, Mockito.times(1))
|
Mockito.verify(mockedController, Mockito.times(1))
|
||||||
.estimatePasswordStrength(eq("qstring"));
|
.estimatePasswordStrength(eq("qstrong"));
|
||||||
testStrengthMeter("qweak", QUITE_WEAK, StrengthMeter.YELLOW);
|
testStrengthMeter("qweak", QUITE_WEAK, StrengthMeter.YELLOW);
|
||||||
Mockito.verify(mockedController, Mockito.times(1))
|
Mockito.verify(mockedController, Mockito.times(1))
|
||||||
.estimatePasswordStrength(eq("qweak"));
|
.estimatePasswordStrength(eq("qweak"));
|
||||||
|
|||||||
@@ -196,7 +196,7 @@ public class SetupActivityTest {
|
|||||||
// Mock answers for UI testing only
|
// Mock answers for UI testing only
|
||||||
when(mockedController.estimatePasswordStrength("strong")).thenReturn(
|
when(mockedController.estimatePasswordStrength("strong")).thenReturn(
|
||||||
STRONG);
|
STRONG);
|
||||||
when(mockedController.estimatePasswordStrength("qstring")).thenReturn(
|
when(mockedController.estimatePasswordStrength("qstrong")).thenReturn(
|
||||||
QUITE_STRONG);
|
QUITE_STRONG);
|
||||||
when(mockedController.estimatePasswordStrength("qweak")).thenReturn(
|
when(mockedController.estimatePasswordStrength("qweak")).thenReturn(
|
||||||
QUITE_WEAK);
|
QUITE_WEAK);
|
||||||
@@ -208,9 +208,9 @@ public class SetupActivityTest {
|
|||||||
testStrengthMeter("strong", STRONG, StrengthMeter.GREEN);
|
testStrengthMeter("strong", STRONG, StrengthMeter.GREEN);
|
||||||
Mockito.verify(mockedController, Mockito.times(1))
|
Mockito.verify(mockedController, Mockito.times(1))
|
||||||
.estimatePasswordStrength(eq("strong"));
|
.estimatePasswordStrength(eq("strong"));
|
||||||
testStrengthMeter("qstring", QUITE_STRONG, StrengthMeter.LIME);
|
testStrengthMeter("qstrong", QUITE_STRONG, StrengthMeter.LIME);
|
||||||
Mockito.verify(mockedController, Mockito.times(1))
|
Mockito.verify(mockedController, Mockito.times(1))
|
||||||
.estimatePasswordStrength(eq("qstring"));
|
.estimatePasswordStrength(eq("qstrong"));
|
||||||
testStrengthMeter("qweak", QUITE_WEAK, StrengthMeter.YELLOW);
|
testStrengthMeter("qweak", QUITE_WEAK, StrengthMeter.YELLOW);
|
||||||
Mockito.verify(mockedController, Mockito.times(1))
|
Mockito.verify(mockedController, Mockito.times(1))
|
||||||
.estimatePasswordStrength(eq("qweak"));
|
.estimatePasswordStrength(eq("qweak"));
|
||||||
|
|||||||
Reference in New Issue
Block a user