Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 7 additions & 6 deletions app/src/main/java/app/notesr/activity/security/AuthHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,14 @@
@RequiredArgsConstructor
public final class AuthHandler {
private static final int MAX_ATTEMPTS = 3;
private static final int ON_WRONG_PASSWORD_DELAY_MS = 1500;
private static final int DELAY_AFTER_AUTH_FAILED = 1500;

private final AuthActivity activity;
private final AppSecurityService appSecurityService;
private final SecretsRotationService secretsRotationService;
private final SecureStringBuilder passwordBuilder;

private int attempts = MAX_ATTEMPTS;
private int authAttempts = MAX_ATTEMPTS;
private char[] createdPassword;

public void authenticate() {
Expand Down Expand Up @@ -181,9 +181,9 @@ private void onAuthenticationSuccessful() {
}

private void onAuthenticationFailed() {
attempts--;
authAttempts--;

if (attempts == 0) {
if (authAttempts == 0) {
try {
appSecurityService.blockApp();
} catch (AppSecurityException e) {
Expand All @@ -193,16 +193,17 @@ private void onAuthenticationFailed() {
showToastMessage(R.string.blocked);
activity.startActivity(new Intent(activity.getApplicationContext(),
KeyRecoveryActivity.class));
activity.finish();
} else {
try {
Thread.sleep(ON_WRONG_PASSWORD_DELAY_MS);
Thread.sleep(DELAY_AFTER_AUTH_FAILED);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}

showToastMessage(String.format(
activity.getString(R.string.wrong_code_you_have_n_attempts),
attempts));
authAttempts));
}

resetPassword();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
import static app.notesr.core.util.CharUtils.charsToBytes;
import static app.notesr.core.util.KeyUtils.getKeyBytesFromKeyHex;

import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.text.Editable;
Expand All @@ -30,17 +29,16 @@
import app.notesr.service.security.AppSecurityException;
import app.notesr.service.security.AppSecurityService;

import java.io.IOException;
import java.nio.charset.CharacterCodingException;
import java.nio.charset.StandardCharsets;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.Objects;

public final class KeyRecoveryActivity extends ActivityBase {
private static final String TAG = KeyRecoveryActivity.class.toString();
private static final String TAG = KeyRecoveryActivity.class.getSimpleName();

private AppSecurityService appSecurityService;
private EditText hexKeyField;

@Override
protected void onCreate(Bundle savedInstanceState) {
Expand All @@ -53,21 +51,31 @@ protected void onCreate(Bundle savedInstanceState) {
ActionBar actionBar = getSupportActionBar();
Objects.requireNonNull(actionBar).setTitle(getString(R.string.key_recovery));

EditText hexKeyField = findViewById(R.id.importRecoveryKeyField);
hexKeyField = findViewById(R.id.importRecoveryKeyField);
Button applyButton = findViewById(R.id.applyRecoveryKeyButton);

disableBackButton(this);

hexKeyField.setImeOptions(IME_FLAG_NO_PERSONALIZED_LEARNING);
applyButton.setOnClickListener(applyButtonOnClick(hexKeyField));
applyButton.setOnClickListener(getApplyButtonOnClickListener());
}

@Override
protected boolean requiresSession() {
return false;
}

private View.OnClickListener applyButtonOnClick(EditText hexKeyField) {
@Override
public void finish() {
if (hexKeyField != null) {
hexKeyField.getText().replace(0, hexKeyField.getText().length(), "");
hexKeyField.setText("");
}

super.finish();
}

private View.OnClickListener getApplyButtonOnClickListener() {
return view -> {
Editable hexKeyEditable = hexKeyField.getText();
int hexKeyLength = hexKeyEditable.length();
Expand All @@ -77,56 +85,49 @@ private View.OnClickListener applyButtonOnClick(EditText hexKeyField) {
hexKeyEditable.getChars(0, hexKeyLength, hexKey, 0);

try {
apply(hexKeyField, hexKey);
if (isMatch(hexKey)) {
proceedKeyMatch(hexKey);
} else {
proceedKeyMismatch();
}
} catch (IllegalArgumentException e) {
Log.e(TAG, "Invalid key", e);
showToastMessage(this, getString(R.string.invalid_key),
Toast.LENGTH_SHORT);
} catch (CharacterCodingException e) {
throw new RuntimeException(e);
} catch (IOException | NoSuchAlgorithmException e) {
} catch (AppSecurityException | CharacterCodingException e) {
Log.e(TAG, e.toString());
throw new RuntimeException(e);
} finally {
Arrays.fill(hexKey, '\0');
}
}
};
}

private void apply(EditText hexKeyField, char[] hexKey)
throws IOException, NoSuchAlgorithmException {

char[] hexKeyCopy = Arrays.copyOf(hexKey, hexKey.length);
byte[] keyBytes = getKeyBytesFromKeyHex(hexKeyCopy);
private boolean isMatch(char[] hexKey) {
byte[] keyBytes = getKeyBytesFromKeyHex(Arrays.copyOf(hexKey, hexKey.length));
boolean isMatch = appSecurityService.isKeyMatchingWithStored(keyBytes);

Context context = getApplicationContext();

try {
if (appSecurityService.isKeyMatchingWithStored(keyBytes)) {
byte[] hexKeyBytes = charsToBytes(hexKey, StandardCharsets.UTF_8);
SecretCache.put(AuthActivity.CACHE_KEY_HEX_KEY, hexKeyBytes);
Arrays.fill(keyBytes, (byte) 0);
return isMatch;
}

// The hex key has already been wiped by charsToBytes
wipeSecretData(keyBytes, hexKeyField);
private void proceedKeyMatch(char[] hexKey) throws CharacterCodingException {
byte[] hexKeyBytes = charsToBytes(Arrays.copyOf(hexKey, hexKey.length),
StandardCharsets.UTF_8);
SecretCache.put(AuthActivity.CACHE_KEY_HEX_KEY, hexKeyBytes);

var targetMode = AuthActivity.Mode.KEY_RECOVERY;
var authActivityIntent = new Intent(context, AuthActivity.class)
.putExtra(AuthActivity.EXTRA_MODE, targetMode.toString());
var targetMode = AuthActivity.Mode.KEY_RECOVERY;
var authActivityIntent = new Intent(getApplicationContext(), AuthActivity.class)
.putExtra(AuthActivity.EXTRA_MODE, targetMode.toString());

startActivity(authActivityIntent);
finish();
} else {
showToastMessage(this,
getString(R.string.wrong_key),
Toast.LENGTH_SHORT);
}
} catch (AppSecurityException e) {
throw new RuntimeException(e);
}
startActivity(authActivityIntent);
finish();
}

private void wipeSecretData(byte[] keyBytes, EditText keyField) {
Arrays.fill(keyBytes, (byte) 0);
keyField.getText().replace(0, keyField.getText().length(), "");
keyField.setText("");
private void proceedKeyMismatch() {
showToastMessage(this,
getString(R.string.wrong_key),
Toast.LENGTH_SHORT);
}
}
Loading