mirror of
https://github.com/beemdevelopment/Aegis.git
synced 2025-04-19 21:39:18 +00:00
Replace the custom fingerprint auth UI with BiometricPrompt
This patch replaces the usage of the deprecated FingerprintManager API with BiometricPrompt. This uses the Android X library, so we get the native biometric prompt on recent versions of Android and a Google-made one on older versions. By not working with custom prompts for biometric authentication like we do now, we can be sure that any issues like #70, #81, #237 are not actually our fault. Here's what it looks like:  As a nice aside, this also adds support for the new facial recognition as an authentication method on Pixel 4 phones. This is still a draft, but early feedback is welcome.
This commit is contained in:
parent
a93ced6e34
commit
3be9aecb88
39 changed files with 499 additions and 716 deletions
2
.github/ISSUE_TEMPLATE/bug.md
vendored
2
.github/ISSUE_TEMPLATE/bug.md
vendored
|
@ -11,7 +11,7 @@ guidelines](/CONTRIBUTING.md#bug-reports) before submitting an issue. -->
|
|||
|
||||
* __Version__:
|
||||
* __Source__: (Google Play/GitHub/F-Droid/?)
|
||||
* __Vault encrypted:__ Yes (with fingerprint unlock)/Yes/No
|
||||
* __Vault encrypted:__ Yes (with biometric unlock)/Yes/No
|
||||
* __Device:__
|
||||
* __Android version and ROM:__
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ document](docs/vault.md).
|
|||
- Secure
|
||||
- Encryption (AES-256)
|
||||
- Password (scrypt)
|
||||
- Fingerprint (Android Keystore)
|
||||
- Biometrics (Android Keystore)
|
||||
- Screen capture prevention
|
||||
- Tap to reveal ability
|
||||
- Multiple ways to add new entries
|
||||
|
@ -120,7 +120,6 @@ Certificate fingerprints:
|
|||
- [AppIntro](https://github.com/AppIntro/AppIntro) by Paolo Rotolo
|
||||
- [Krop](https://github.com/avito-tech/krop) by Avito Technology
|
||||
- [SpongyCastle](https://github.com/rtyley/spongycastle) by Roberto Tyley
|
||||
- [Swirl](https://github.com/mattprecious/swirl) by Matthew Precious
|
||||
- [CircleImageView](https://github.com/hdodenhof/CircleImageView) by Henning
|
||||
Dodenhof
|
||||
- [barcodescanner](https://github.com/dm77/barcodescanner) by Dushyanth
|
||||
|
|
|
@ -67,6 +67,7 @@ dependencies {
|
|||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||
implementation 'com.amulyakhare:com.amulyakhare.textdrawable:1.0.1'
|
||||
implementation 'androidx.appcompat:appcompat:1.1.0'
|
||||
implementation "androidx.biometric:biometric:1.0.0"
|
||||
implementation 'androidx.cardview:cardview:1.0.0'
|
||||
implementation 'androidx.preference:preference:1.1.0'
|
||||
implementation 'com.google.android.material:material:1.0.0'
|
||||
|
@ -75,7 +76,6 @@ dependencies {
|
|||
implementation 'com.github.apl-devs:appintro:5.1.0'
|
||||
implementation 'com.github.avito-tech:krop:0.44'
|
||||
implementation 'com.madgag.spongycastle:core:1.58.0.0'
|
||||
implementation 'com.mattprecious.swirl:swirl:1.2.0'
|
||||
implementation 'de.hdodenhof:circleimageview:3.0.1'
|
||||
implementation 'me.dm7.barcodescanner:zxing:1.9.8'
|
||||
implementation "com.github.topjohnwu.libsu:core:${libsuVersion}"
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
package="com.beemdevelopment.aegis">
|
||||
|
||||
<uses-permission android:name="android.permission.CAMERA" />
|
||||
<uses-permission android:name="android.permission.USE_FINGERPRINT" />
|
||||
<uses-permission android:name="android.permission.USE_BIOMETRIC" />
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
|
||||
|
|
|
@ -4,17 +4,17 @@ import com.beemdevelopment.aegis.crypto.CryptParameters;
|
|||
|
||||
import java.util.UUID;
|
||||
|
||||
public class FingerprintSlot extends RawSlot {
|
||||
public FingerprintSlot() {
|
||||
public class BiometricSlot extends RawSlot {
|
||||
public BiometricSlot() {
|
||||
super();
|
||||
}
|
||||
|
||||
FingerprintSlot(UUID uuid, byte[] key, CryptParameters keyParams) {
|
||||
BiometricSlot(UUID uuid, byte[] key, CryptParameters keyParams) {
|
||||
super(uuid, key, keyParams);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte getType() {
|
||||
return TYPE_FINGERPRINT;
|
||||
return TYPE_BIOMETRIC;
|
||||
}
|
||||
}
|
|
@ -28,7 +28,7 @@ import javax.crypto.spec.SecretKeySpec;
|
|||
public abstract class Slot extends UUIDMap.Value {
|
||||
public final static byte TYPE_RAW = 0x00;
|
||||
public final static byte TYPE_DERIVED = 0x01;
|
||||
public final static byte TYPE_FINGERPRINT = 0x02;
|
||||
public final static byte TYPE_BIOMETRIC = 0x02;
|
||||
|
||||
private byte[] _encryptedMasterKey;
|
||||
private CryptParameters _encryptedMasterKeyParams;
|
||||
|
@ -138,8 +138,8 @@ public abstract class Slot extends UUIDMap.Value {
|
|||
boolean repaired = obj.optBoolean("repaired", false);
|
||||
slot = new PasswordSlot(uuid, key, keyParams, scryptParams, repaired);
|
||||
break;
|
||||
case Slot.TYPE_FINGERPRINT:
|
||||
slot = new FingerprintSlot(uuid, key, keyParams);
|
||||
case Slot.TYPE_BIOMETRIC:
|
||||
slot = new BiometricSlot(uuid, key, keyParams);
|
||||
break;
|
||||
default:
|
||||
throw new SlotException("unrecognized slot type");
|
||||
|
|
|
@ -0,0 +1,136 @@
|
|||
package com.beemdevelopment.aegis.helpers;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.biometric.BiometricPrompt;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
|
||||
import com.beemdevelopment.aegis.crypto.KeyStoreHandle;
|
||||
import com.beemdevelopment.aegis.crypto.KeyStoreHandleException;
|
||||
import com.beemdevelopment.aegis.db.slots.BiometricSlot;
|
||||
import com.beemdevelopment.aegis.db.slots.Slot;
|
||||
import com.beemdevelopment.aegis.db.slots.SlotException;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.SecretKey;
|
||||
|
||||
/**
|
||||
* A class that can prepare initialization of a BiometricSlot by generating a new
|
||||
* key in the Android KeyStore and authenticating a cipher for it through a
|
||||
* BiometricPrompt.
|
||||
*/
|
||||
public class BiometricSlotInitializer extends BiometricPrompt.AuthenticationCallback {
|
||||
private BiometricSlot _slot;
|
||||
private Listener _listener;
|
||||
private BiometricPrompt _prompt;
|
||||
|
||||
public BiometricSlotInitializer(Fragment fragment, Listener listener) {
|
||||
_listener = listener;
|
||||
_prompt = new BiometricPrompt(fragment, new UiThreadExecutor(), this);
|
||||
}
|
||||
|
||||
public BiometricSlotInitializer(FragmentActivity activity, Listener listener) {
|
||||
_listener = listener;
|
||||
_prompt = new BiometricPrompt(activity, new UiThreadExecutor(), this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a new key in the Android KeyStore for the new BiometricSlot,
|
||||
* initializes a cipher with it and shows a BiometricPrompt to the user for
|
||||
* authentication. If authentication is successful, the new slot will be
|
||||
* initialized and delivered back through the listener.
|
||||
*/
|
||||
public void authenticate(BiometricPrompt.PromptInfo info) {
|
||||
if (_slot != null) {
|
||||
throw new IllegalStateException("Biometric authentication already in progress");
|
||||
}
|
||||
|
||||
KeyStoreHandle keyStore;
|
||||
try {
|
||||
keyStore = new KeyStoreHandle();
|
||||
} catch (KeyStoreHandleException e) {
|
||||
fail(e);
|
||||
return;
|
||||
}
|
||||
|
||||
// generate a new Android KeyStore key
|
||||
// and assign it the UUID of the new slot as an alias
|
||||
Cipher cipher;
|
||||
BiometricSlot slot = new BiometricSlot();
|
||||
try {
|
||||
SecretKey key = keyStore.generateKey(slot.getUUID().toString());
|
||||
cipher = Slot.createEncryptCipher(key);
|
||||
} catch (KeyStoreHandleException | SlotException e) {
|
||||
fail(e);
|
||||
return;
|
||||
}
|
||||
|
||||
_slot = slot;
|
||||
_prompt.authenticate(info, new BiometricPrompt.CryptoObject(cipher));
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancels the BiometricPrompt and resets the state of the initializer. It will
|
||||
* also attempt to delete the previously generated Android KeyStore key.
|
||||
*/
|
||||
public void cancelAuthentication() {
|
||||
if (_slot == null) {
|
||||
throw new IllegalStateException("Biometric authentication not in progress");
|
||||
}
|
||||
|
||||
reset();
|
||||
_prompt.cancelAuthentication();
|
||||
}
|
||||
|
||||
private void reset() {
|
||||
if (_slot != null) {
|
||||
try {
|
||||
// clean up the unused KeyStore key
|
||||
// this is non-critical, so just fail silently if an error occurs
|
||||
String uuid = _slot.getUUID().toString();
|
||||
KeyStoreHandle keyStore = new KeyStoreHandle();
|
||||
if (keyStore.containsKey(uuid)) {
|
||||
keyStore.deleteKey(uuid);
|
||||
}
|
||||
} catch (KeyStoreHandleException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
_slot = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void fail(int errorCode, CharSequence errString) {
|
||||
reset();
|
||||
_listener.onSlotInitializationFailed(errorCode, errString);
|
||||
}
|
||||
|
||||
private void fail(Exception e) {
|
||||
e.printStackTrace();
|
||||
fail(0, e.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAuthenticationError(int errorCode, @NonNull CharSequence errString) {
|
||||
super.onAuthenticationError(errorCode, errString);
|
||||
fail(errorCode, errString.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAuthenticationSucceeded(@NonNull BiometricPrompt.AuthenticationResult result) {
|
||||
super.onAuthenticationSucceeded(result);
|
||||
_listener.onInitializeSlot(_slot, Objects.requireNonNull(result.getCryptoObject()).getCipher());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAuthenticationFailed() {
|
||||
super.onAuthenticationFailed();
|
||||
}
|
||||
|
||||
public interface Listener {
|
||||
void onInitializeSlot(BiometricSlot slot, Cipher cipher);
|
||||
void onSlotInitializationFailed(int errorCode, @NonNull CharSequence errString);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
package com.beemdevelopment.aegis.helpers;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.biometric.BiometricConstants;
|
||||
import androidx.biometric.BiometricManager;
|
||||
|
||||
public class BiometricsHelper {
|
||||
private BiometricsHelper() {
|
||||
|
||||
}
|
||||
|
||||
public static BiometricManager getManager(Context context) {
|
||||
BiometricManager manager = BiometricManager.from(context);
|
||||
if (manager.canAuthenticate() == BiometricManager.BIOMETRIC_SUCCESS) {
|
||||
return manager;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static boolean isCanceled(int errorCode) {
|
||||
return errorCode == BiometricConstants.ERROR_CANCELED
|
||||
|| errorCode == BiometricConstants.ERROR_USER_CANCELED
|
||||
|| errorCode == BiometricConstants.ERROR_NEGATIVE_BUTTON;
|
||||
}
|
||||
|
||||
public static boolean isAvailable(Context context) {
|
||||
return getManager(context) != null;
|
||||
}
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
package com.beemdevelopment.aegis.helpers;
|
||||
|
||||
import android.Manifest;
|
||||
import android.content.Context;
|
||||
import android.hardware.fingerprint.FingerprintManager;
|
||||
import android.os.Build;
|
||||
|
||||
import androidx.annotation.RequiresApi;
|
||||
|
||||
public class FingerprintHelper {
|
||||
private FingerprintHelper() {
|
||||
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.M)
|
||||
public static FingerprintManager getManager(Context context) {
|
||||
if (PermissionHelper.granted(context, Manifest.permission.USE_FINGERPRINT)) {
|
||||
FingerprintManager manager = (FingerprintManager) context.getSystemService(Context.FINGERPRINT_SERVICE);
|
||||
if (manager != null && manager.isHardwareDetected() && manager.hasEnrolledFingerprints()) {
|
||||
return manager;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.M)
|
||||
public static boolean isAvailable(Context context) {
|
||||
return getManager(context) != null;
|
||||
}
|
||||
|
||||
public static boolean isSupported() {
|
||||
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.M;
|
||||
}
|
||||
}
|
|
@ -1,156 +0,0 @@
|
|||
// This file was originally taken from https://github.com/googlesamples/android-FingerprintDialog/blob/2feb02945ae220ebd1bc2c2b620a1d43e30daea8/Application/src/main/java/com/example/android/fingerprintdialog/FingerprintUiHelper.java
|
||||
// It has been modified to suit Aegis' needs
|
||||
|
||||
/*
|
||||
* Copyright (C) 2015 The Android Open Source Project
|
||||
*
|
||||
* 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 com.beemdevelopment.aegis.helpers;
|
||||
|
||||
import android.hardware.fingerprint.FingerprintManager;
|
||||
import android.os.Build;
|
||||
import android.os.CancellationSignal;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.beemdevelopment.aegis.R;
|
||||
import com.mattprecious.swirl.SwirlView;
|
||||
|
||||
import androidx.annotation.RequiresApi;
|
||||
|
||||
/**
|
||||
* Small helper class to manage text/icon around fingerprint authentication UI.
|
||||
*/
|
||||
@RequiresApi(api = Build.VERSION_CODES.M)
|
||||
public class FingerprintUiHelper extends FingerprintManager.AuthenticationCallback {
|
||||
|
||||
private static final long ERROR_TIMEOUT_MILLIS = 1600;
|
||||
private static final long SUCCESS_DELAY_MILLIS = 100;
|
||||
|
||||
private final FingerprintManager mFingerprintManager;
|
||||
private final SwirlView mIcon;
|
||||
private final TextView mErrorTextView;
|
||||
private final Callback mCallback;
|
||||
private CancellationSignal mCancellationSignal;
|
||||
|
||||
private boolean mSelfCancelled;
|
||||
|
||||
/**
|
||||
* Constructor for {@link FingerprintUiHelper}.
|
||||
*/
|
||||
public FingerprintUiHelper(FingerprintManager fingerprintManager,
|
||||
SwirlView icon, TextView errorTextView, Callback callback) {
|
||||
mFingerprintManager = fingerprintManager;
|
||||
mIcon = icon;
|
||||
mErrorTextView = errorTextView;
|
||||
mCallback = callback;
|
||||
}
|
||||
|
||||
public boolean isFingerprintAuthAvailable() {
|
||||
// The line below prevents the false positive inspection from Android Studio
|
||||
// noinspection ResourceType
|
||||
return mFingerprintManager.isHardwareDetected()
|
||||
&& mFingerprintManager.hasEnrolledFingerprints();
|
||||
}
|
||||
|
||||
public void startListening(FingerprintManager.CryptoObject cryptoObject) {
|
||||
if (!isFingerprintAuthAvailable()) {
|
||||
return;
|
||||
}
|
||||
mCancellationSignal = new CancellationSignal();
|
||||
mSelfCancelled = false;
|
||||
// The line below prevents the false positive inspection from Android Studio
|
||||
// noinspection ResourceType
|
||||
mFingerprintManager
|
||||
.authenticate(cryptoObject, mCancellationSignal, 0 /* flags */, this, null);
|
||||
mIcon.setState(SwirlView.State.ON);
|
||||
}
|
||||
|
||||
public void stopListening() {
|
||||
if (mCancellationSignal != null) {
|
||||
mSelfCancelled = true;
|
||||
mCancellationSignal.cancel();
|
||||
mCancellationSignal = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAuthenticationError(int errMsgId, CharSequence errString) {
|
||||
if (!mSelfCancelled) {
|
||||
showError(errString);
|
||||
mIcon.postDelayed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mCallback.onError();
|
||||
}
|
||||
}, ERROR_TIMEOUT_MILLIS);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAuthenticationHelp(int helpMsgId, CharSequence helpString) {
|
||||
showError(helpString);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAuthenticationFailed() {
|
||||
showError(mIcon.getResources().getString(
|
||||
R.string.fingerprint_not_recognized));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAuthenticationSucceeded(FingerprintManager.AuthenticationResult result) {
|
||||
mErrorTextView.removeCallbacks(mResetErrorTextRunnable);
|
||||
mIcon.setState(SwirlView.State.OFF);
|
||||
mErrorTextView.setText(
|
||||
mErrorTextView.getResources().getString(R.string.fingerprint_success));
|
||||
mIcon.postDelayed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mCallback.onAuthenticated();
|
||||
}
|
||||
}, SUCCESS_DELAY_MILLIS);
|
||||
|
||||
// ugly hack to keep the fingerprint icon visible while also giving visual feedback of success to the user
|
||||
mIcon.postDelayed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mIcon.setState(SwirlView.State.ON);
|
||||
}
|
||||
}, 500);
|
||||
}
|
||||
|
||||
private void showError(CharSequence error) {
|
||||
mIcon.setState(SwirlView.State.ERROR);
|
||||
mErrorTextView.setText(error);
|
||||
mErrorTextView.removeCallbacks(mResetErrorTextRunnable);
|
||||
mErrorTextView.postDelayed(mResetErrorTextRunnable, ERROR_TIMEOUT_MILLIS);
|
||||
}
|
||||
|
||||
private Runnable mResetErrorTextRunnable = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mErrorTextView.setText(
|
||||
mErrorTextView.getResources().getString(R.string.fingerprint_hint));
|
||||
mIcon.setState(SwirlView.State.ON);
|
||||
}
|
||||
};
|
||||
|
||||
public interface Callback {
|
||||
|
||||
void onAuthenticated();
|
||||
|
||||
void onError();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
package com.beemdevelopment.aegis.helpers;
|
||||
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
public class UiThreadExecutor implements Executor {
|
||||
private final Handler _handler = new Handler(Looper.getMainLooper());
|
||||
|
||||
@Override
|
||||
public void execute(@NonNull Runnable command) {
|
||||
_handler.post(command);
|
||||
}
|
||||
}
|
|
@ -1,61 +1,56 @@
|
|||
package com.beemdevelopment.aegis.ui;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.hardware.fingerprint.FingerprintManager;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.WindowManager;
|
||||
import android.view.inputmethod.EditorInfo;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
import android.widget.Button;
|
||||
import android.widget.EditText;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.biometric.BiometricPrompt;
|
||||
|
||||
import com.beemdevelopment.aegis.R;
|
||||
import com.beemdevelopment.aegis.CancelAction;
|
||||
import com.beemdevelopment.aegis.R;
|
||||
import com.beemdevelopment.aegis.crypto.KeyStoreHandle;
|
||||
import com.beemdevelopment.aegis.crypto.KeyStoreHandleException;
|
||||
import com.beemdevelopment.aegis.db.DatabaseFileCredentials;
|
||||
import com.beemdevelopment.aegis.db.slots.FingerprintSlot;
|
||||
import com.beemdevelopment.aegis.db.slots.BiometricSlot;
|
||||
import com.beemdevelopment.aegis.db.slots.PasswordSlot;
|
||||
import com.beemdevelopment.aegis.db.slots.Slot;
|
||||
import com.beemdevelopment.aegis.db.slots.SlotException;
|
||||
import com.beemdevelopment.aegis.db.slots.SlotList;
|
||||
import com.beemdevelopment.aegis.helpers.BiometricsHelper;
|
||||
import com.beemdevelopment.aegis.helpers.EditTextHelper;
|
||||
import com.beemdevelopment.aegis.helpers.FingerprintHelper;
|
||||
import com.beemdevelopment.aegis.helpers.FingerprintUiHelper;
|
||||
import com.beemdevelopment.aegis.helpers.UiThreadExecutor;
|
||||
import com.beemdevelopment.aegis.ui.tasks.SlotListTask;
|
||||
import com.mattprecious.swirl.SwirlView;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.SecretKey;
|
||||
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
|
||||
public class AuthActivity extends AegisActivity implements FingerprintUiHelper.Callback, SlotListTask.Callback {
|
||||
public class AuthActivity extends AegisActivity implements SlotListTask.Callback {
|
||||
private EditText _textPassword;
|
||||
|
||||
private CancelAction _cancelAction;
|
||||
private SlotList _slots;
|
||||
private FingerprintUiHelper _fingerHelper;
|
||||
private FingerprintManager.CryptoObject _fingerCryptoObj;
|
||||
private BiometricPrompt.CryptoObject _bioCryptoObj;
|
||||
private BiometricPrompt _bioPrompt;
|
||||
|
||||
@Override
|
||||
@SuppressLint("NewApi")
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_auth);
|
||||
_textPassword = findViewById(R.id.text_password);
|
||||
LinearLayout boxFingerprint = findViewById(R.id.box_fingerprint);
|
||||
LinearLayout boxFingerprintInfo = findViewById(R.id.box_fingerprint_info);
|
||||
TextView textFingerprint = findViewById(R.id.text_fingerprint);
|
||||
LinearLayout boxBiometricInfo = findViewById(R.id.box_biometric_info);
|
||||
Button decryptButton = findViewById(R.id.button_decrypt);
|
||||
Button biometricsButton = findViewById(R.id.button_biometrics);
|
||||
|
||||
_textPassword.setOnEditorActionListener((v, actionId, event) -> {
|
||||
if ((event != null && (event.getKeyCode() == KeyEvent.KEYCODE_ENTER)) || (actionId == EditorInfo.IME_ACTION_DONE)) {
|
||||
|
@ -64,25 +59,17 @@ public class AuthActivity extends AegisActivity implements FingerprintUiHelper.C
|
|||
return false;
|
||||
});
|
||||
|
||||
SwirlView imgFingerprint = null;
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
ViewGroup insertPoint = findViewById(R.id.img_fingerprint_insert);
|
||||
imgFingerprint = new SwirlView(this);
|
||||
insertPoint.addView(imgFingerprint, 0, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
|
||||
}
|
||||
|
||||
Intent intent = getIntent();
|
||||
_slots = (SlotList) intent.getSerializableExtra("slots");
|
||||
_cancelAction = (CancelAction) intent.getSerializableExtra("cancelAction");
|
||||
|
||||
// only show the fingerprint controls if the api version is new enough, permission is granted, a scanner is found and a fingerprint slot is found
|
||||
if (_slots.has(FingerprintSlot.class) && FingerprintHelper.isSupported() && FingerprintHelper.isAvailable(this)) {
|
||||
// only show the biometric prompt if the api version is new enough, permission is granted, a scanner is found and a biometric slot is found
|
||||
if (_slots.has(BiometricSlot.class) && BiometricsHelper.isAvailable(this)) {
|
||||
boolean invalidated = false;
|
||||
FingerprintManager manager = FingerprintHelper.getManager(this);
|
||||
|
||||
try {
|
||||
// find a fingerprint slot with an id that matches an alias in the keystore
|
||||
for (FingerprintSlot slot : _slots.findAll(FingerprintSlot.class)) {
|
||||
// find a biometric slot with an id that matches an alias in the keystore
|
||||
for (BiometricSlot slot : _slots.findAll(BiometricSlot.class)) {
|
||||
String id = slot.getUUID().toString();
|
||||
KeyStoreHandle handle = new KeyStoreHandle();
|
||||
if (handle.containsKey(id)) {
|
||||
|
@ -92,10 +79,11 @@ public class AuthActivity extends AegisActivity implements FingerprintUiHelper.C
|
|||
invalidated = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
Cipher cipher = slot.createDecryptCipher(key);
|
||||
_fingerCryptoObj = new FingerprintManager.CryptoObject(cipher);
|
||||
_fingerHelper = new FingerprintUiHelper(manager, imgFingerprint, textFingerprint, this);
|
||||
boxFingerprint.setVisibility(View.VISIBLE);
|
||||
_bioCryptoObj = new BiometricPrompt.CryptoObject(cipher);
|
||||
_bioPrompt = new BiometricPrompt(this, new UiThreadExecutor(), new BiometricPromptListener());
|
||||
biometricsButton.setVisibility(View.VISIBLE);
|
||||
invalidated = false;
|
||||
break;
|
||||
}
|
||||
|
@ -106,7 +94,7 @@ public class AuthActivity extends AegisActivity implements FingerprintUiHelper.C
|
|||
|
||||
// display a help message if a matching invalidated keystore entry was found
|
||||
if (invalidated) {
|
||||
boxFingerprintInfo.setVisibility(View.VISIBLE);
|
||||
boxBiometricInfo.setVisibility(View.VISIBLE);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -121,7 +109,11 @@ public class AuthActivity extends AegisActivity implements FingerprintUiHelper.C
|
|||
}
|
||||
});
|
||||
|
||||
if (_fingerHelper == null) {
|
||||
biometricsButton.setOnClickListener(v -> {
|
||||
showBiometricPrompt();
|
||||
});
|
||||
|
||||
if (_bioCryptoObj == null) {
|
||||
_textPassword.requestFocus();
|
||||
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
|
||||
}
|
||||
|
@ -162,36 +154,31 @@ public class AuthActivity extends AegisActivity implements FingerprintUiHelper.C
|
|||
}
|
||||
|
||||
@Override
|
||||
@SuppressLint("NewApi")
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
|
||||
if (_fingerHelper != null) {
|
||||
_fingerHelper.startListening(_fingerCryptoObj);
|
||||
if (_bioPrompt != null) {
|
||||
showBiometricPrompt();
|
||||
}
|
||||
}
|
||||
|
||||
public void showBiometricPrompt() {
|
||||
BiometricPrompt.PromptInfo info = new BiometricPrompt.PromptInfo.Builder()
|
||||
.setTitle(getString(R.string.authentication))
|
||||
.setNegativeButtonText(getString(android.R.string.cancel))
|
||||
.build();
|
||||
_bioPrompt.authenticate(info, _bioCryptoObj);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressLint("NewApi")
|
||||
public void onPause() {
|
||||
super.onPause();
|
||||
|
||||
if (_fingerHelper != null) {
|
||||
_fingerHelper.stopListening();
|
||||
if (_bioPrompt != null) {
|
||||
_bioPrompt.cancelAuthentication();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressLint("NewApi")
|
||||
public void onAuthenticated() {
|
||||
trySlots(FingerprintSlot.class, _fingerCryptoObj.getCipher());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTaskFinished(SlotListTask.Result result) {
|
||||
if (result != null) {
|
||||
|
@ -210,4 +197,25 @@ public class AuthActivity extends AegisActivity implements FingerprintUiHelper.C
|
|||
showError();
|
||||
}
|
||||
}
|
||||
|
||||
private class BiometricPromptListener extends BiometricPrompt.AuthenticationCallback {
|
||||
@Override
|
||||
public void onAuthenticationError(int errorCode, @NonNull CharSequence errString) {
|
||||
super.onAuthenticationError(errorCode, errString);
|
||||
if (!BiometricsHelper.isCanceled(errorCode)) {
|
||||
Toast.makeText(AuthActivity.this, errString, Toast.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAuthenticationSucceeded(@NonNull BiometricPrompt.AuthenticationResult result) {
|
||||
super.onAuthenticationSucceeded(result);
|
||||
trySlots(BiometricSlot.class, _bioCryptoObj.getCipher());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAuthenticationFailed() {
|
||||
super.onAuthenticationFailed();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,8 +4,6 @@ import android.app.Activity;
|
|||
import android.app.Dialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.hardware.fingerprint.FingerprintManager;
|
||||
import android.os.Build;
|
||||
import android.text.Editable;
|
||||
import android.text.InputType;
|
||||
import android.text.TextWatcher;
|
||||
|
@ -18,30 +16,21 @@ import android.widget.CheckBox;
|
|||
import android.widget.CompoundButton;
|
||||
import android.widget.EditText;
|
||||
import android.widget.NumberPicker;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.StringRes;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
|
||||
import com.beemdevelopment.aegis.Preferences;
|
||||
import com.beemdevelopment.aegis.R;
|
||||
import com.beemdevelopment.aegis.crypto.KeyStoreHandle;
|
||||
import com.beemdevelopment.aegis.crypto.KeyStoreHandleException;
|
||||
import com.beemdevelopment.aegis.db.slots.FingerprintSlot;
|
||||
import com.beemdevelopment.aegis.db.slots.PasswordSlot;
|
||||
import com.beemdevelopment.aegis.db.slots.Slot;
|
||||
import com.beemdevelopment.aegis.db.slots.SlotException;
|
||||
import com.beemdevelopment.aegis.helpers.EditTextHelper;
|
||||
import com.beemdevelopment.aegis.helpers.FingerprintHelper;
|
||||
import com.beemdevelopment.aegis.helpers.FingerprintUiHelper;
|
||||
import com.beemdevelopment.aegis.ui.tasks.DerivationTask;
|
||||
import com.mattprecious.swirl.SwirlView;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.SecretKey;
|
||||
|
||||
import androidx.annotation.RequiresApi;
|
||||
import androidx.annotation.StringRes;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
|
||||
public class Dialogs {
|
||||
private Dialogs() {
|
||||
|
@ -195,52 +184,6 @@ public class Dialogs {
|
|||
showSecureDialog(dialog);
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.M)
|
||||
public static void showFingerprintDialog(Activity activity, Dialogs.SlotListener listener) {
|
||||
View view = activity.getLayoutInflater().inflate(R.layout.dialog_fingerprint, null);
|
||||
TextView textFingerprint = view.findViewById(R.id.text_fingerprint);
|
||||
SwirlView imgFingerprint = view.findViewById(R.id.img_fingerprint);
|
||||
|
||||
FingerprintManager.CryptoObject obj;
|
||||
FingerprintSlot slot;
|
||||
final AtomicReference<FingerprintUiHelper> helper = new AtomicReference<>();
|
||||
FingerprintManager manager = FingerprintHelper.getManager(activity);
|
||||
|
||||
try {
|
||||
slot = new FingerprintSlot();
|
||||
SecretKey key = new KeyStoreHandle().generateKey(slot.getUUID().toString());
|
||||
Cipher cipher = Slot.createEncryptCipher(key);
|
||||
obj = new FingerprintManager.CryptoObject(cipher);
|
||||
} catch (KeyStoreHandleException | SlotException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
AlertDialog dialog = new AlertDialog.Builder(activity)
|
||||
.setTitle(R.string.register_fingerprint)
|
||||
.setView(view)
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.setOnDismissListener(d -> {
|
||||
helper.get().stopListening();
|
||||
})
|
||||
.create();
|
||||
|
||||
helper.set(new FingerprintUiHelper(manager, imgFingerprint, textFingerprint, new FingerprintUiHelper.Callback() {
|
||||
@Override
|
||||
public void onAuthenticated() {
|
||||
listener.onSlotResult(slot, obj.getCipher());
|
||||
dialog.dismiss();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError() {
|
||||
|
||||
}
|
||||
}));
|
||||
|
||||
helper.get().startListening(obj);
|
||||
showSecureDialog(dialog);
|
||||
}
|
||||
|
||||
public interface NumberInputListener {
|
||||
void onNumberInputResult(int number);
|
||||
}
|
||||
|
|
|
@ -4,6 +4,8 @@ import android.content.Intent;
|
|||
import android.os.Bundle;
|
||||
import android.view.WindowManager;
|
||||
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import com.beemdevelopment.aegis.Preferences;
|
||||
import com.beemdevelopment.aegis.R;
|
||||
import com.beemdevelopment.aegis.db.Database;
|
||||
|
@ -12,11 +14,10 @@ import com.beemdevelopment.aegis.db.DatabaseFileCredentials;
|
|||
import com.beemdevelopment.aegis.db.DatabaseFileException;
|
||||
import com.beemdevelopment.aegis.db.DatabaseManager;
|
||||
import com.beemdevelopment.aegis.db.DatabaseManagerException;
|
||||
import com.beemdevelopment.aegis.db.slots.FingerprintSlot;
|
||||
import com.beemdevelopment.aegis.db.slots.BiometricSlot;
|
||||
import com.beemdevelopment.aegis.db.slots.PasswordSlot;
|
||||
import com.beemdevelopment.aegis.db.slots.Slot;
|
||||
import com.beemdevelopment.aegis.db.slots.SlotException;
|
||||
import com.beemdevelopment.aegis.db.slots.SlotList;
|
||||
import com.beemdevelopment.aegis.ui.slides.CustomAuthenticatedSlide;
|
||||
import com.beemdevelopment.aegis.ui.slides.CustomAuthenticationSlide;
|
||||
import com.beemdevelopment.aegis.ui.tasks.DerivationTask;
|
||||
|
@ -29,8 +30,6 @@ import org.json.JSONObject;
|
|||
import javax.crypto.Cipher;
|
||||
import javax.crypto.SecretKey;
|
||||
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
public class IntroActivity extends AppIntro2 implements DerivationTask.Callback {
|
||||
public static final int RESULT_OK = 0;
|
||||
public static final int RESULT_EXCEPTION = 1;
|
||||
|
@ -135,7 +134,6 @@ public class IntroActivity extends AppIntro2 implements DerivationTask.Callback
|
|||
creds = new DatabaseFileCredentials();
|
||||
}
|
||||
|
||||
SlotList slots = null;
|
||||
if (cryptType != CustomAuthenticationSlide.CRYPT_TYPE_NONE) {
|
||||
// encrypt the master key with a key derived from the user's password
|
||||
// and add it to the list of slots
|
||||
|
@ -150,18 +148,14 @@ public class IntroActivity extends AppIntro2 implements DerivationTask.Callback
|
|||
}
|
||||
}
|
||||
|
||||
if (cryptType == CustomAuthenticationSlide.CRYPT_TYPE_FINGER) {
|
||||
if (cryptType == CustomAuthenticationSlide.CRYPT_TYPE_BIOMETRIC) {
|
||||
BiometricSlot slot = _authenticatedSlide.getBiometricSlot();
|
||||
try {
|
||||
// encrypt the master key with the fingerprint key
|
||||
// and add it to the list of slots
|
||||
FingerprintSlot slot = _authenticatedSlide.getFingerSlot();
|
||||
Cipher cipher = _authenticatedSlide.getFingerCipher();
|
||||
slot.setKey(creds.getKey(), cipher);
|
||||
creds.getSlots().add(slot);
|
||||
slot.setKey(creds.getKey(), _authenticatedSlide.getBiometriCipher());
|
||||
} catch (SlotException e) {
|
||||
setException(e);
|
||||
return;
|
||||
}
|
||||
creds.getSlots().add(slot);
|
||||
}
|
||||
|
||||
// finally, save the database
|
||||
|
|
|
@ -12,6 +12,12 @@ import android.view.Window;
|
|||
import android.view.WindowManager;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.biometric.BiometricPrompt;
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceFragmentCompat;
|
||||
|
||||
import com.beemdevelopment.aegis.AegisApplication;
|
||||
import com.beemdevelopment.aegis.BuildConfig;
|
||||
import com.beemdevelopment.aegis.CancelAction;
|
||||
|
@ -25,12 +31,13 @@ import com.beemdevelopment.aegis.db.DatabaseFileCredentials;
|
|||
import com.beemdevelopment.aegis.db.DatabaseFileException;
|
||||
import com.beemdevelopment.aegis.db.DatabaseManager;
|
||||
import com.beemdevelopment.aegis.db.DatabaseManagerException;
|
||||
import com.beemdevelopment.aegis.db.slots.FingerprintSlot;
|
||||
import com.beemdevelopment.aegis.db.slots.BiometricSlot;
|
||||
import com.beemdevelopment.aegis.db.slots.PasswordSlot;
|
||||
import com.beemdevelopment.aegis.db.slots.Slot;
|
||||
import com.beemdevelopment.aegis.db.slots.SlotException;
|
||||
import com.beemdevelopment.aegis.db.slots.SlotList;
|
||||
import com.beemdevelopment.aegis.helpers.FingerprintHelper;
|
||||
import com.beemdevelopment.aegis.helpers.BiometricSlotInitializer;
|
||||
import com.beemdevelopment.aegis.helpers.BiometricsHelper;
|
||||
import com.beemdevelopment.aegis.helpers.PermissionHelper;
|
||||
import com.beemdevelopment.aegis.importers.AegisImporter;
|
||||
import com.beemdevelopment.aegis.importers.DatabaseImporter;
|
||||
|
@ -56,10 +63,6 @@ import java.util.concurrent.atomic.AtomicReference;
|
|||
|
||||
import javax.crypto.Cipher;
|
||||
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceFragmentCompat;
|
||||
|
||||
public class PreferencesFragment extends PreferenceFragmentCompat {
|
||||
// activity request codes
|
||||
private static final int CODE_IMPORT = 0;
|
||||
|
@ -81,7 +84,7 @@ public class PreferencesFragment extends PreferenceFragmentCompat {
|
|||
private UUIDMap<DatabaseEntry> _importerEntries;
|
||||
|
||||
private SwitchPreference _encryptionPreference;
|
||||
private SwitchPreference _fingerprintPreference;
|
||||
private SwitchPreference _biometricsPreference;
|
||||
private Preference _autoLockPreference;
|
||||
private Preference _setPasswordPreference;
|
||||
private Preference _slotsPreference;
|
||||
|
@ -289,20 +292,25 @@ public class PreferencesFragment extends PreferenceFragmentCompat {
|
|||
}
|
||||
});
|
||||
|
||||
_fingerprintPreference = (SwitchPreference) findPreference("pref_fingerprint");
|
||||
_fingerprintPreference.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
|
||||
_biometricsPreference = (SwitchPreference) findPreference("pref_biometrics");
|
||||
_biometricsPreference.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
|
||||
@Override
|
||||
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
||||
DatabaseFileCredentials creds = _db.getCredentials();
|
||||
SlotList slots = creds.getSlots();
|
||||
|
||||
if (!slots.has(FingerprintSlot.class)) {
|
||||
if (FingerprintHelper.isSupported() && FingerprintHelper.isAvailable(getContext())) {
|
||||
Dialogs.showFingerprintDialog(getActivity(), new RegisterFingerprintListener());
|
||||
if (!slots.has(BiometricSlot.class)) {
|
||||
if (BiometricsHelper.isAvailable(getContext())) {
|
||||
BiometricSlotInitializer initializer = new BiometricSlotInitializer(PreferencesFragment.this, new RegisterBiometricsListener());
|
||||
BiometricPrompt.PromptInfo info = new BiometricPrompt.PromptInfo.Builder()
|
||||
.setTitle(getString(R.string.set_up_biometric))
|
||||
.setNegativeButtonText(getString(android.R.string.cancel))
|
||||
.build();
|
||||
initializer.authenticate(info);
|
||||
}
|
||||
} else {
|
||||
// remove the fingerprint slot
|
||||
FingerprintSlot slot = slots.find(FingerprintSlot.class);
|
||||
// remove the biometric slot
|
||||
BiometricSlot slot = slots.find(BiometricSlot.class);
|
||||
slots.remove(slot);
|
||||
_db.setCredentials(creds);
|
||||
|
||||
|
@ -676,24 +684,24 @@ public class PreferencesFragment extends PreferenceFragmentCompat {
|
|||
boolean encrypted = _db.isEncryptionEnabled();
|
||||
_encryptionPreference.setChecked(encrypted, true);
|
||||
_setPasswordPreference.setVisible(encrypted);
|
||||
_fingerprintPreference.setVisible(encrypted);
|
||||
_biometricsPreference.setVisible(encrypted);
|
||||
_slotsPreference.setEnabled(encrypted);
|
||||
_autoLockPreference.setVisible(encrypted);
|
||||
|
||||
if (encrypted) {
|
||||
SlotList slots = _db.getCredentials().getSlots();
|
||||
boolean multiPassword = slots.findAll(PasswordSlot.class).size() > 1;
|
||||
boolean multiFinger = slots.findAll(FingerprintSlot.class).size() > 1;
|
||||
boolean showSlots = BuildConfig.DEBUG || multiPassword || multiFinger;
|
||||
boolean canUseFinger = FingerprintHelper.isSupported() && FingerprintHelper.isAvailable(getContext());
|
||||
boolean multiBio = slots.findAll(BiometricSlot.class).size() > 1;
|
||||
boolean showSlots = BuildConfig.DEBUG || multiPassword || multiBio;
|
||||
boolean canUseBio = BiometricsHelper.isAvailable(getContext());
|
||||
_setPasswordPreference.setEnabled(!multiPassword);
|
||||
_fingerprintPreference.setEnabled(canUseFinger && !multiFinger);
|
||||
_fingerprintPreference.setChecked(slots.has(FingerprintSlot.class), true);
|
||||
_biometricsPreference.setEnabled(canUseBio && !multiBio);
|
||||
_biometricsPreference.setChecked(slots.has(BiometricSlot.class), true);
|
||||
_slotsPreference.setVisible(showSlots);
|
||||
} else {
|
||||
_setPasswordPreference.setEnabled(false);
|
||||
_fingerprintPreference.setEnabled(false);
|
||||
_fingerprintPreference.setChecked(false, true);
|
||||
_biometricsPreference.setEnabled(false);
|
||||
_biometricsPreference.setChecked(false, true);
|
||||
_slotsPreference.setVisible(false);
|
||||
}
|
||||
}
|
||||
|
@ -730,20 +738,17 @@ public class PreferencesFragment extends PreferenceFragmentCompat {
|
|||
}
|
||||
}
|
||||
|
||||
private class RegisterFingerprintListener implements Dialogs.SlotListener {
|
||||
private class RegisterBiometricsListener implements BiometricSlotInitializer.Listener {
|
||||
@Override
|
||||
public void onSlotResult(Slot slot, Cipher cipher) {
|
||||
public void onInitializeSlot(BiometricSlot slot, Cipher cipher) {
|
||||
DatabaseFileCredentials creds = _db.getCredentials();
|
||||
SlotList slots = creds.getSlots();
|
||||
|
||||
try {
|
||||
slot.setKey(creds.getKey(), cipher);
|
||||
} catch (SlotException e) {
|
||||
onException(e);
|
||||
onSlotInitializationFailed(0, e.toString());
|
||||
return;
|
||||
}
|
||||
|
||||
slots.add(slot);
|
||||
creds.getSlots().add(slot);
|
||||
_db.setCredentials(creds);
|
||||
|
||||
saveDatabase();
|
||||
|
@ -751,8 +756,10 @@ public class PreferencesFragment extends PreferenceFragmentCompat {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void onException(Exception e) {
|
||||
Toast.makeText(getActivity(), getString(R.string.encryption_enable_fingerprint_error) + e.getMessage(), Toast.LENGTH_SHORT).show();
|
||||
public void onSlotInitializationFailed(int errorCode, @NonNull CharSequence errString) {
|
||||
if (!BiometricsHelper.isCanceled(errorCode)) {
|
||||
Toast.makeText(getActivity(), String.format("%s: %s", getString(R.string.encryption_enable_biometrics_error), errString), Toast.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,26 +7,29 @@ import android.view.MenuItem;
|
|||
import android.view.View;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.ActionBar;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.biometric.BiometricPrompt;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.beemdevelopment.aegis.R;
|
||||
import com.beemdevelopment.aegis.crypto.KeyStoreHandle;
|
||||
import com.beemdevelopment.aegis.crypto.KeyStoreHandleException;
|
||||
import com.beemdevelopment.aegis.db.DatabaseFileCredentials;
|
||||
import com.beemdevelopment.aegis.db.slots.FingerprintSlot;
|
||||
import com.beemdevelopment.aegis.db.slots.BiometricSlot;
|
||||
import com.beemdevelopment.aegis.db.slots.PasswordSlot;
|
||||
import com.beemdevelopment.aegis.db.slots.Slot;
|
||||
import com.beemdevelopment.aegis.db.slots.SlotException;
|
||||
import com.beemdevelopment.aegis.db.slots.SlotList;
|
||||
import com.beemdevelopment.aegis.helpers.FingerprintHelper;
|
||||
import com.beemdevelopment.aegis.helpers.BiometricSlotInitializer;
|
||||
import com.beemdevelopment.aegis.helpers.BiometricsHelper;
|
||||
import com.beemdevelopment.aegis.ui.views.SlotAdapter;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
|
||||
import androidx.appcompat.app.ActionBar;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
public class SlotManagerActivity extends AegisActivity implements SlotAdapter.Listener, Dialogs.SlotListener {
|
||||
public class SlotManagerActivity extends AegisActivity implements SlotAdapter.Listener {
|
||||
private DatabaseFileCredentials _creds;
|
||||
private SlotAdapter _adapter;
|
||||
|
||||
|
@ -42,14 +45,19 @@ public class SlotManagerActivity extends AegisActivity implements SlotAdapter.Li
|
|||
bar.setHomeAsUpIndicator(R.drawable.ic_close);
|
||||
bar.setDisplayHomeAsUpEnabled(true);
|
||||
|
||||
findViewById(R.id.button_add_fingerprint).setOnClickListener(view -> {
|
||||
if (FingerprintHelper.isSupported() && FingerprintHelper.isAvailable(this)) {
|
||||
Dialogs.showFingerprintDialog(this ,this);
|
||||
findViewById(R.id.button_add_biometric).setOnClickListener(view -> {
|
||||
if (BiometricsHelper.isAvailable(this)) {
|
||||
BiometricSlotInitializer initializer = new BiometricSlotInitializer(SlotManagerActivity.this, new RegisterBiometricsListener());
|
||||
BiometricPrompt.PromptInfo info = new BiometricPrompt.PromptInfo.Builder()
|
||||
.setTitle(getString(R.string.add_biometric_slot))
|
||||
.setNegativeButtonText(getString(android.R.string.cancel))
|
||||
.build();
|
||||
initializer.authenticate(info);
|
||||
}
|
||||
});
|
||||
|
||||
findViewById(R.id.button_add_password).setOnClickListener(view -> {
|
||||
Dialogs.showSetPasswordDialog(this, this);
|
||||
Dialogs.showSetPasswordDialog(this, new PasswordListener());
|
||||
});
|
||||
|
||||
// set up the recycler view
|
||||
|
@ -66,17 +74,17 @@ public class SlotManagerActivity extends AegisActivity implements SlotAdapter.Li
|
|||
_adapter.addSlot(slot);
|
||||
}
|
||||
|
||||
updateFingerprintButton();
|
||||
updateBiometricsButton();
|
||||
}
|
||||
|
||||
private void updateFingerprintButton() {
|
||||
// only show the fingerprint option if we can get an instance of the fingerprint manager
|
||||
private void updateBiometricsButton() {
|
||||
// only show the biometrics option if we can get an instance of the biometrics manager
|
||||
// and if none of the slots in the collection has a matching alias in the keystore
|
||||
int visibility = View.VISIBLE;
|
||||
if (FingerprintHelper.isSupported() && FingerprintHelper.isAvailable(this)) {
|
||||
if (BiometricsHelper.isAvailable(this)) {
|
||||
try {
|
||||
KeyStoreHandle keyStore = new KeyStoreHandle();
|
||||
for (FingerprintSlot slot : _creds.getSlots().findAll(FingerprintSlot.class)) {
|
||||
for (BiometricSlot slot : _creds.getSlots().findAll(BiometricSlot.class)) {
|
||||
if (keyStore.containsKey(slot.getUUID().toString())) {
|
||||
visibility = View.GONE;
|
||||
break;
|
||||
|
@ -88,7 +96,7 @@ public class SlotManagerActivity extends AegisActivity implements SlotAdapter.Li
|
|||
} else {
|
||||
visibility = View.GONE;
|
||||
}
|
||||
findViewById(R.id.button_add_fingerprint).setVisibility(visibility);
|
||||
findViewById(R.id.button_add_biometric).setVisibility(visibility);
|
||||
}
|
||||
|
||||
private void onSave() {
|
||||
|
@ -164,12 +172,45 @@ public class SlotManagerActivity extends AegisActivity implements SlotAdapter.Li
|
|||
slots.remove(slot);
|
||||
_adapter.removeSlot(slot);
|
||||
_edited = true;
|
||||
updateFingerprintButton();
|
||||
updateBiometricsButton();
|
||||
})
|
||||
.setNegativeButton(android.R.string.no, null)
|
||||
.create());
|
||||
}
|
||||
|
||||
private void addSlot(Slot slot) {
|
||||
_creds.getSlots().add(slot);
|
||||
_adapter.addSlot(slot);
|
||||
_edited = true;
|
||||
updateBiometricsButton();
|
||||
}
|
||||
|
||||
private void showSlotError(String error) {
|
||||
Toast.makeText(SlotManagerActivity.this, getString(R.string.adding_new_slot_error) + error, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
private class RegisterBiometricsListener implements BiometricSlotInitializer.Listener {
|
||||
|
||||
@Override
|
||||
public void onInitializeSlot(BiometricSlot slot, Cipher cipher) {
|
||||
try {
|
||||
slot.setKey(_creds.getKey(), cipher);
|
||||
addSlot(slot);
|
||||
} catch (SlotException e) {
|
||||
onSlotInitializationFailed(0, e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSlotInitializationFailed(int errorCode, @NonNull CharSequence errString) {
|
||||
if (!BiometricsHelper.isCanceled(errorCode)) {
|
||||
showSlotError(errString.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class PasswordListener implements Dialogs.SlotListener {
|
||||
|
||||
@Override
|
||||
public void onSlotResult(Slot slot, Cipher cipher) {
|
||||
try {
|
||||
|
@ -179,14 +220,12 @@ public class SlotManagerActivity extends AegisActivity implements SlotAdapter.Li
|
|||
return;
|
||||
}
|
||||
|
||||
_creds.getSlots().add(slot);
|
||||
_adapter.addSlot(slot);
|
||||
_edited = true;
|
||||
updateFingerprintButton();
|
||||
addSlot(slot);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onException(Exception e) {
|
||||
Toast.makeText(this, getString(R.string.adding_new_slot_error) + e.getMessage(), Toast.LENGTH_SHORT).show();
|
||||
showSlotError(e.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,53 +1,39 @@
|
|||
package com.beemdevelopment.aegis.ui.slides;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.hardware.fingerprint.FingerprintManager;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.text.method.PasswordTransformationMethod;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.CompoundButton;
|
||||
import android.widget.EditText;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.biometric.BiometricPrompt;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import com.beemdevelopment.aegis.R;
|
||||
import com.beemdevelopment.aegis.crypto.KeyStoreHandle;
|
||||
import com.beemdevelopment.aegis.crypto.KeyStoreHandleException;
|
||||
import com.beemdevelopment.aegis.db.slots.FingerprintSlot;
|
||||
import com.beemdevelopment.aegis.db.slots.Slot;
|
||||
import com.beemdevelopment.aegis.db.slots.BiometricSlot;
|
||||
import com.beemdevelopment.aegis.helpers.BiometricSlotInitializer;
|
||||
import com.beemdevelopment.aegis.helpers.BiometricsHelper;
|
||||
import com.beemdevelopment.aegis.helpers.EditTextHelper;
|
||||
import com.beemdevelopment.aegis.helpers.FingerprintUiHelper;
|
||||
import com.github.paolorotolo.appintro.ISlidePolicy;
|
||||
import com.github.paolorotolo.appintro.ISlideSelectionListener;
|
||||
import com.google.android.material.snackbar.Snackbar;
|
||||
import com.mattprecious.swirl.SwirlView;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.SecretKey;
|
||||
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
public class CustomAuthenticatedSlide extends Fragment implements FingerprintUiHelper.Callback, ISlidePolicy, ISlideSelectionListener {
|
||||
public class CustomAuthenticatedSlide extends Fragment implements ISlidePolicy, ISlideSelectionListener {
|
||||
private int _cryptType;
|
||||
private EditText _textPassword;
|
||||
private EditText _textPasswordConfirm;
|
||||
private CheckBox _checkPasswordVisibility;
|
||||
private int _bgColor;
|
||||
|
||||
private LinearLayout _boxFingerprint;
|
||||
private SwirlView _imgFingerprint;
|
||||
private TextView _textFingerprint;
|
||||
private FingerprintUiHelper _fingerHelper;
|
||||
private KeyStoreHandle _storeHandle;
|
||||
private FingerprintSlot _fingerSlot;
|
||||
private FingerprintManager.CryptoObject _fingerCryptoObj;
|
||||
private boolean _fingerAuthenticated;
|
||||
private BiometricSlot _bioSlot;
|
||||
private Cipher _bioCipher;
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
|
@ -55,13 +41,6 @@ public class CustomAuthenticatedSlide extends Fragment implements FingerprintUiH
|
|||
_textPassword = view.findViewById(R.id.text_password);
|
||||
_textPasswordConfirm = view.findViewById(R.id.text_password_confirm);
|
||||
_checkPasswordVisibility = view.findViewById(R.id.check_toggle_visibility);
|
||||
_boxFingerprint = view.findViewById(R.id.box_fingerprint);
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
ViewGroup insertPoint = view.findViewById(R.id.img_fingerprint_insert);
|
||||
_imgFingerprint = new SwirlView(getContext());
|
||||
insertPoint.addView(_imgFingerprint, 0, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
|
||||
}
|
||||
|
||||
_checkPasswordVisibility.setOnCheckedChangeListener((buttonView, isChecked) -> {
|
||||
if (isChecked) {
|
||||
|
@ -74,7 +53,6 @@ public class CustomAuthenticatedSlide extends Fragment implements FingerprintUiH
|
|||
}
|
||||
});
|
||||
|
||||
_textFingerprint = view.findViewById(R.id.text_fingerprint);
|
||||
view.findViewById(R.id.main).setBackgroundColor(_bgColor);
|
||||
return view;
|
||||
}
|
||||
|
@ -83,73 +61,44 @@ public class CustomAuthenticatedSlide extends Fragment implements FingerprintUiH
|
|||
return _cryptType;
|
||||
}
|
||||
|
||||
public BiometricSlot getBiometricSlot() {
|
||||
return _bioSlot;
|
||||
}
|
||||
|
||||
public Cipher getBiometriCipher() {
|
||||
return _bioCipher;
|
||||
}
|
||||
|
||||
public char[] getPassword() {
|
||||
return EditTextHelper.getEditTextChars(_textPassword);
|
||||
}
|
||||
|
||||
@SuppressLint("NewApi")
|
||||
public Cipher getFingerCipher() {
|
||||
return _fingerCryptoObj.getCipher();
|
||||
}
|
||||
|
||||
public FingerprintSlot getFingerSlot() {
|
||||
return _fingerSlot;
|
||||
}
|
||||
|
||||
public void setBgColor(int color) {
|
||||
_bgColor = color;
|
||||
}
|
||||
|
||||
public void showBiometricPrompt() {
|
||||
BiometricSlotInitializer initializer = new BiometricSlotInitializer(this, new BiometricsListener());
|
||||
BiometricPrompt.PromptInfo info = new BiometricPrompt.PromptInfo.Builder()
|
||||
.setTitle(getString(R.string.set_up_biometric))
|
||||
.setNegativeButtonText(getString(android.R.string.cancel))
|
||||
.build();
|
||||
initializer.authenticate(info);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressLint("NewApi")
|
||||
public void onSlideSelected() {
|
||||
Intent intent = getActivity().getIntent();
|
||||
_cryptType = intent.getIntExtra("cryptType", CustomAuthenticationSlide.CRYPT_TYPE_INVALID);
|
||||
|
||||
switch(_cryptType) {
|
||||
case CustomAuthenticationSlide.CRYPT_TYPE_NONE:
|
||||
case CustomAuthenticationSlide.CRYPT_TYPE_PASS:
|
||||
break;
|
||||
case CustomAuthenticationSlide.CRYPT_TYPE_FINGER:
|
||||
_boxFingerprint.setVisibility(View.VISIBLE);
|
||||
|
||||
SecretKey key;
|
||||
try {
|
||||
if (_storeHandle == null) {
|
||||
_storeHandle = new KeyStoreHandle();
|
||||
_fingerSlot = new FingerprintSlot();
|
||||
}
|
||||
key = _storeHandle.generateKey(_fingerSlot.getUUID().toString());
|
||||
} catch (KeyStoreHandleException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
if (_fingerHelper == null) {
|
||||
FingerprintManager fingerManager = (FingerprintManager) getContext().getSystemService(Context.FINGERPRINT_SERVICE);
|
||||
_fingerHelper = new FingerprintUiHelper(fingerManager, _imgFingerprint, _textFingerprint, this);
|
||||
}
|
||||
|
||||
try {
|
||||
Cipher cipher = Slot.createEncryptCipher(key);
|
||||
_fingerCryptoObj = new FingerprintManager.CryptoObject(cipher);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
_fingerHelper.startListening(_fingerCryptoObj);
|
||||
break;
|
||||
default:
|
||||
throw new RuntimeException();
|
||||
if (_cryptType == CustomAuthenticationSlide.CRYPT_TYPE_BIOMETRIC) {
|
||||
showBiometricPrompt();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressLint("NewApi")
|
||||
public void onSlideDeselected() {
|
||||
if (_fingerHelper != null) {
|
||||
_fingerAuthenticated = false;
|
||||
_boxFingerprint.setVisibility(View.INVISIBLE);
|
||||
_fingerHelper.stopListening();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -157,8 +106,8 @@ public class CustomAuthenticatedSlide extends Fragment implements FingerprintUiH
|
|||
switch (_cryptType) {
|
||||
case CustomAuthenticationSlide.CRYPT_TYPE_NONE:
|
||||
return true;
|
||||
case CustomAuthenticationSlide.CRYPT_TYPE_FINGER:
|
||||
if (!_fingerAuthenticated) {
|
||||
case CustomAuthenticationSlide.CRYPT_TYPE_BIOMETRIC:
|
||||
if (_bioSlot == null) {
|
||||
return false;
|
||||
}
|
||||
// intentional fallthrough
|
||||
|
@ -169,7 +118,7 @@ public class CustomAuthenticatedSlide extends Fragment implements FingerprintUiH
|
|||
|
||||
return false;
|
||||
default:
|
||||
throw new RuntimeException();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -178,26 +127,30 @@ public class CustomAuthenticatedSlide extends Fragment implements FingerprintUiH
|
|||
String message;
|
||||
if (!EditTextHelper.areEditTextsEqual(_textPassword, _textPasswordConfirm) && !_checkPasswordVisibility.isChecked()) {
|
||||
message = getString(R.string.password_equality_error);
|
||||
} else if (!_fingerAuthenticated) {
|
||||
message = getString(R.string.register_fingerprint);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
View view = getView();
|
||||
if (view != null) {
|
||||
Snackbar snackbar = Snackbar.make(view, message, Snackbar.LENGTH_LONG);
|
||||
snackbar.show();
|
||||
}
|
||||
} else if (_bioSlot == null) {
|
||||
showBiometricPrompt();
|
||||
}
|
||||
}
|
||||
|
||||
private class BiometricsListener implements BiometricSlotInitializer.Listener {
|
||||
|
||||
@Override
|
||||
public void onInitializeSlot(BiometricSlot slot, Cipher cipher) {
|
||||
_bioSlot = slot;
|
||||
_bioCipher = cipher;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAuthenticated() {
|
||||
_fingerAuthenticated = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError() {
|
||||
|
||||
public void onSlotInitializationFailed(int errorCode, @NonNull CharSequence errString) {
|
||||
if (!BiometricsHelper.isCanceled(errorCode)) {
|
||||
Toast.makeText(CustomAuthenticatedSlide.this.getContext(), errString, Toast.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
package com.beemdevelopment.aegis.ui.slides;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Intent;
|
||||
import android.hardware.fingerprint.FingerprintManager;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
|
@ -11,18 +9,18 @@ import android.widget.RadioButton;
|
|||
import android.widget.RadioGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import com.beemdevelopment.aegis.R;
|
||||
import com.beemdevelopment.aegis.helpers.FingerprintHelper;
|
||||
import com.beemdevelopment.aegis.helpers.BiometricsHelper;
|
||||
import com.github.paolorotolo.appintro.ISlidePolicy;
|
||||
import com.google.android.material.snackbar.Snackbar;
|
||||
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
public class CustomAuthenticationSlide extends Fragment implements ISlidePolicy, RadioGroup.OnCheckedChangeListener {
|
||||
public static final int CRYPT_TYPE_INVALID = 0;
|
||||
public static final int CRYPT_TYPE_NONE = 1;
|
||||
public static final int CRYPT_TYPE_PASS = 2;
|
||||
public static final int CRYPT_TYPE_FINGER = 3;
|
||||
public static final int CRYPT_TYPE_BIOMETRIC = 3;
|
||||
|
||||
private RadioGroup _buttonGroup;
|
||||
private int _bgColor;
|
||||
|
@ -35,9 +33,9 @@ public class CustomAuthenticationSlide extends Fragment implements ISlidePolicy,
|
|||
onCheckedChanged(_buttonGroup, _buttonGroup.getCheckedRadioButtonId());
|
||||
|
||||
// only enable the fingerprint option if the api version is new enough, permission is granted and a scanner is found
|
||||
if (FingerprintHelper.isSupported() && FingerprintHelper.isAvailable(getContext())) {
|
||||
RadioButton button = view.findViewById(R.id.rb_fingerprint);
|
||||
TextView text = view.findViewById(R.id.text_rb_fingerprint);
|
||||
if (BiometricsHelper.isAvailable(getContext())) {
|
||||
RadioButton button = view.findViewById(R.id.rb_biometrics);
|
||||
TextView text = view.findViewById(R.id.text_rb_biometrics);
|
||||
button.setEnabled(true);
|
||||
text.setEnabled(true);
|
||||
}
|
||||
|
@ -75,8 +73,8 @@ public class CustomAuthenticationSlide extends Fragment implements ISlidePolicy,
|
|||
case R.id.rb_password:
|
||||
id = CRYPT_TYPE_PASS;
|
||||
break;
|
||||
case R.id.rb_fingerprint:
|
||||
id = CRYPT_TYPE_FINGER;
|
||||
case R.id.rb_biometrics:
|
||||
id = CRYPT_TYPE_BIOMETRIC;
|
||||
break;
|
||||
default:
|
||||
throw new RuntimeException();
|
||||
|
|
|
@ -6,7 +6,7 @@ import android.content.Context;
|
|||
import com.beemdevelopment.aegis.R;
|
||||
import com.beemdevelopment.aegis.crypto.CryptoUtils;
|
||||
import com.beemdevelopment.aegis.crypto.MasterKey;
|
||||
import com.beemdevelopment.aegis.db.slots.FingerprintSlot;
|
||||
import com.beemdevelopment.aegis.db.slots.BiometricSlot;
|
||||
import com.beemdevelopment.aegis.db.slots.PasswordSlot;
|
||||
import com.beemdevelopment.aegis.db.slots.Slot;
|
||||
import com.beemdevelopment.aegis.db.slots.SlotException;
|
||||
|
@ -38,8 +38,8 @@ public class SlotListTask<T extends Slot> extends ProgressDialogTask<SlotListTas
|
|||
if (slot instanceof PasswordSlot) {
|
||||
char[] password = (char[]) params.getObj();
|
||||
return decryptPasswordSlot((PasswordSlot) slot, password);
|
||||
} else if (slot instanceof FingerprintSlot) {
|
||||
return decryptFingerprintSlot((FingerprintSlot) slot, (Cipher) params.getObj());
|
||||
} else if (slot instanceof BiometricSlot) {
|
||||
return decryptBiometricSlot((BiometricSlot) slot, (Cipher) params.getObj());
|
||||
}
|
||||
} catch (SlotException e) {
|
||||
throw new RuntimeException(e);
|
||||
|
@ -51,7 +51,7 @@ public class SlotListTask<T extends Slot> extends ProgressDialogTask<SlotListTas
|
|||
return null;
|
||||
}
|
||||
|
||||
private Result decryptFingerprintSlot(FingerprintSlot slot, Cipher cipher)
|
||||
private Result decryptBiometricSlot(BiometricSlot slot, Cipher cipher)
|
||||
throws SlotException, SlotIntegrityException {
|
||||
MasterKey key = slot.getKey(cipher);
|
||||
return new Result(key, slot);
|
||||
|
|
|
@ -5,16 +5,16 @@ import android.widget.ImageView;
|
|||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.beemdevelopment.aegis.R;
|
||||
import com.beemdevelopment.aegis.crypto.KeyStoreHandle;
|
||||
import com.beemdevelopment.aegis.crypto.KeyStoreHandleException;
|
||||
import com.beemdevelopment.aegis.db.slots.FingerprintSlot;
|
||||
import com.beemdevelopment.aegis.db.slots.BiometricSlot;
|
||||
import com.beemdevelopment.aegis.db.slots.PasswordSlot;
|
||||
import com.beemdevelopment.aegis.db.slots.RawSlot;
|
||||
import com.beemdevelopment.aegis.db.slots.Slot;
|
||||
import com.beemdevelopment.aegis.helpers.FingerprintHelper;
|
||||
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import com.beemdevelopment.aegis.helpers.BiometricsHelper;
|
||||
|
||||
public class SlotHolder extends RecyclerView.ViewHolder {
|
||||
private TextView _slotUsed;
|
||||
|
@ -36,10 +36,10 @@ public class SlotHolder extends RecyclerView.ViewHolder {
|
|||
if (slot instanceof PasswordSlot) {
|
||||
_slotName.setText(R.string.password);
|
||||
_slotImg.setImageResource(R.drawable.ic_create_black_24dp);
|
||||
} else if (slot instanceof FingerprintSlot) {
|
||||
_slotName.setText(R.string.authentication_method_fingerprint);
|
||||
} else if (slot instanceof BiometricSlot) {
|
||||
_slotName.setText(R.string.authentication_method_biometrics);
|
||||
_slotImg.setImageResource(R.drawable.ic_fingerprint_black_24dp);
|
||||
if (FingerprintHelper.isSupported()) {
|
||||
if (BiometricsHelper.isAvailable(itemView.getContext())) {
|
||||
try {
|
||||
KeyStoreHandle keyStore = new KeyStoreHandle();
|
||||
if (keyStore.containsKey(slot.getUUID().toString())) {
|
||||
|
|
|
@ -49,40 +49,29 @@
|
|||
android:inputType="textPassword" />
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
<Button
|
||||
android:id="@+id/button_decrypt"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:minWidth="125dp"
|
||||
android:text="@string/unlock" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/box_fingerprint"
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginTop="12dp"
|
||||
android:visibility="gone">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/img_fingerprint_insert"
|
||||
android:layout_width="60dp"
|
||||
android:layout_height="60dp"
|
||||
android:orientation="horizontal"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/text_fingerprint"
|
||||
android:layout_width="match_parent"
|
||||
<Button
|
||||
android:id="@+id/button_biometrics"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginLeft="15dp"
|
||||
android:text="@string/fingerprint_hint"
|
||||
android:textColor="?attr/secondaryText"/>
|
||||
android:minWidth="125dp"
|
||||
android:text="@string/biometrics"
|
||||
android:visibility="gone" />
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/box_fingerprint_info"
|
||||
android:id="@+id/box_biometric_info"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
|
@ -98,7 +87,7 @@
|
|||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/invalidated_fingerprint"/>
|
||||
android:text="@string/invalidated_biometrics"/>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
|
|
|
@ -53,7 +53,7 @@
|
|||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/button_add_fingerprint"
|
||||
android:id="@+id/button_add_biometric"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
|
@ -75,7 +75,7 @@
|
|||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/add_fingerprint"
|
||||
android:text="@string/add_biometric"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
android:textColor="?android:attr/textColorSecondary"/>
|
||||
</LinearLayout>
|
||||
|
|
|
@ -1,21 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingStart="20dp"
|
||||
android:paddingEnd="20dp"
|
||||
android:paddingTop="20dp">
|
||||
<com.mattprecious.swirl.SwirlView
|
||||
android:id="@+id/img_fingerprint"
|
||||
android:layout_width="60dp"
|
||||
android:layout_height="60dp"/>
|
||||
<TextView
|
||||
android:id="@+id/text_fingerprint"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="15dp"
|
||||
android:text="@string/fingerprint_hint"
|
||||
android:textColor="?attr/secondaryText"
|
||||
android:layout_gravity="center_vertical"/>
|
||||
</LinearLayout>
|
|
@ -68,43 +68,4 @@
|
|||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/box_fingerprint"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="20dp"
|
||||
android:visibility="invisible">
|
||||
|
||||
<TextView
|
||||
android:text="@string/authentication_method_fingerprint"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="24sp"
|
||||
android:textColor="@color/primary_text_inverted"/>
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginTop="12dp">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/img_fingerprint_insert"
|
||||
android:layout_width="60dp"
|
||||
android:layout_height="60dp"
|
||||
android:orientation="horizontal"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/text_fingerprint"
|
||||
android:textColor="@color/primary_text_inverted"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginLeft="15dp"
|
||||
android:text="@string/fingerprint_hint"/>
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
|
|
@ -60,22 +60,22 @@
|
|||
android:textColor="@color/secondary_text_inverted" />
|
||||
|
||||
<RadioButton
|
||||
android:id="@+id/rb_fingerprint"
|
||||
android:id="@+id/rb_biometrics"
|
||||
android:enabled="false"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/authentication_method_fingerprint"
|
||||
android:text="@string/authentication_method_biometrics"
|
||||
android:textSize="16sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/text_rb_fingerprint"
|
||||
android:id="@+id/text_rb_biometrics"
|
||||
android:enabled="false"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="32dp"
|
||||
android:layout_marginTop="-5dp"
|
||||
|
||||
android:text="@string/authentication_method_fingerprint_description"
|
||||
android:text="@string/authentication_method_biometrics_description"
|
||||
android:textColor="@color/disabled_textview_colors" />
|
||||
|
||||
</RadioGroup>
|
||||
|
|
|
@ -36,12 +36,6 @@
|
|||
<copyright>Copyright (c) 2000-2017 The Legion of the Bouncy Castle Inc. (http://www.bouncycastle.org)</copyright>
|
||||
<license>Apache Software License 2.0</license>
|
||||
</notice>
|
||||
<notice>
|
||||
<name>Swirl</name>
|
||||
<url>https://github.com/mattprecious/swirl</url>
|
||||
<copyright>Copyright 2016 Matthew Precious</copyright>
|
||||
<license>Apache Software License 2.0</license>
|
||||
</notice>
|
||||
<notice>
|
||||
<name>CircleImageView</name>
|
||||
<url>https://github.com/hdodenhof/CircleImageView</url>
|
||||
|
|
|
@ -38,22 +38,14 @@
|
|||
<string name="pref_auto_lock_summary">Automatische Sperre, wenn die App geschlossen oder dein Gerät gesperrt wird.</string>
|
||||
<string name="pref_encryption_title">Verschlüsselung</string>
|
||||
<string name="pref_encryption_summary">Verschlüssele die Datenbank und entsperre mit einem Passwort oder Fingerabdruck.</string>
|
||||
<string name="pref_fingerprint_title">Fingerabdruck</string>
|
||||
<string name="pref_fingerprint_summary">Ermöglicht es, dass auf diesem Gerät registrierte Fingerabdrücke den Tresor freischalten.</string>
|
||||
<string name="pref_set_password_title">Passwort ändern</string>
|
||||
<string name="pref_set_password_summary">Legen ein neues Passwort fest, das erforderlich ist, um deinen Tresor freizuschalten.</string>
|
||||
|
||||
<string name="fingerprint_hint">Berührungssensor</string>
|
||||
<string name="fingerprint_not_recognized">Fingerabdruck nicht erkannt. Versuche es noch einmal.</string>
|
||||
<string name="fingerprint_success">Fingerabdruck erkannt</string>
|
||||
|
||||
<string name="choose_authentication_method">Sicherheit</string>
|
||||
<string name="authentication_method_none">Keine</string>
|
||||
<string name="authentication_method_none_description">Du brauchst kein Passwort, um den Tresor freizuschalten, und es wird nicht verschlüsselt. Diese Option wird nicht empfohlen.</string>
|
||||
<string name="authentication_method_password">Passwort</string>
|
||||
<string name="authentication_method_password_description">Du benötigst ein Passwort, um den Tresor freizuschalten.</string>
|
||||
<string name="authentication_method_fingerprint">Fingerabdruck</string>
|
||||
<string name="authentication_method_fingerprint_description">Zusätzlich zu einem Passwort können auf diesem Gerät registrierte Fingerabdrücke verwendet werden, um den Tresor freizuschalten.</string>
|
||||
<string name="authentication_method_set_password">Passwort</string>
|
||||
<string name="authentication_enter_password">Gib dein Passwort ein</string>
|
||||
<string name="authentication">Entsperre den Tresor.</string>
|
||||
|
@ -61,7 +53,6 @@
|
|||
<string name="set_group">Bitte gib einen Gruppennamen ein</string>
|
||||
<string name="set_number">Bitte gib eine Zahl ein</string>
|
||||
<string name="set_password_confirm">Bitte bestätige das Passwort</string>
|
||||
<string name="invalidated_fingerprint">Es wurde eine Änderung der Sicherheitseinstellungen deines Geräts festgestellt. Bitte gehe zu \"Aegis -> Einstellungen -> Fingerabdruck\" und füge deinen Fingerabdruck erneut hinzu.</string>
|
||||
|
||||
<string name="unlock">Entsperren</string>
|
||||
<string name="advanced">Fortgeschritten</string>
|
||||
|
@ -72,7 +63,6 @@
|
|||
<string name="scan">QR-Code scannen</string>
|
||||
<string name="scan_image">Bild scannen</string>
|
||||
<string name="enter_manually">Manuell eingeben</string>
|
||||
<string name="add_fingerprint">Fingerabdruck hinzufügen</string>
|
||||
<string name="add_password">Passwort hinzufügen</string>
|
||||
<string name="slots_warning">Der Tresor ist nur so sicher wie dein schwächster Schlüssel. Wenn ein neuer Fingerabdruck zu deinem Gerät hinzugefügt wird, musst du die Fingerabdruck-Authentifizierung in Aegis reaktivieren.</string>
|
||||
<string name="copy">Kopieren</string>
|
||||
|
@ -85,7 +75,6 @@
|
|||
<string name="unlock_vault_error">Der Tresor konnte nicht entsperrt werden.</string>
|
||||
<string name="unlock_vault_error_description">Falsches Passwort. Achte darauf, dass du dein Passwort nicht falsch eingibst.</string>
|
||||
<string name="password_equality_error">Passwörter sollten identisch und nicht leer sein.</string>
|
||||
<string name="register_fingerprint">Registriere deinen Fingerabdruck</string>
|
||||
<string name="snackbar_authentication_method">Bitte wähle eine Authentifizierungsmethode aus</string>
|
||||
<string name="encrypting_vault">Verschlüsseln des Tresors</string>
|
||||
<string name="delete_entry">Eintrag löschen</string>
|
||||
|
@ -124,7 +113,6 @@
|
|||
<string name="export_database_location">Die Datenbank wurde exportiert nach:</string>
|
||||
<string name="export_warning">Diese Aktion exportiert die Datenbank aus dem privaten Speicher von Aegis.</string>
|
||||
<string name="encryption_set_password_error">Beim Versuch, das Passwort festzulegen, ist ein Fehler aufgetreten: </string>
|
||||
<string name="encryption_enable_fingerprint_error">Beim Versuch den Fingerabdruck zu entsperren, ist ein Fehler aufgetreten: </string>
|
||||
<string name="no_cameras_available">Keine Kameras verfügbar</string>
|
||||
<string name="read_qr_error">Beim Versuch, den QR-Code zu lesen, ist ein Fehler aufgetreten.</string>
|
||||
<string name="authentication_method_raw">Raw</string>
|
||||
|
|
|
@ -41,22 +41,14 @@
|
|||
<string name="pref_auto_lock_summary">Verrouiller automatiquement lorsque vous fermez l\'application ou verrouillez votre appareil.</string>
|
||||
<string name="pref_encryption_title">Chiffrement</string>
|
||||
<string name="pref_encryption_summary">Chiffrer la base de données et la déverrouiller avec un mot de passe ou une empreinte digitale</string>
|
||||
<string name="pref_fingerprint_title">Empreinte digitale</string>
|
||||
<string name="pref_fingerprint_summary">Autoriser les empreintes digitales enregistrées sur cet appareil à déverrouiller le coffre-fort</string>
|
||||
<string name="pref_set_password_title">Changer le mot de passe</string>
|
||||
<string name="pref_set_password_summary">Définir un mot de passe dont vous aurez besoin pour déverrouiller votre coffre-fort</string>
|
||||
|
||||
<string name="fingerprint_hint">Appuyez sur le capteur</string>
|
||||
<string name="fingerprint_not_recognized">Empreinte digitale non reconnue. Réessayez.</string>
|
||||
<string name="fingerprint_success">Empreinte digitale reconnue</string>
|
||||
|
||||
<string name="choose_authentication_method">Sécurité</string>
|
||||
<string name="authentication_method_none">Aucun</string>
|
||||
<string name="authentication_method_none_description">Vous n\'avez pas besoin d\'un mot de passe pour déverrouiller le coffre-fort et il ne sera pas chiffré. Cette option n\'est pas recommandée.</string>
|
||||
<string name="authentication_method_password">Mot de passe</string>
|
||||
<string name="authentication_method_password_description">Vous avez besoin d\'un mot de passe pour déverrouiller le coffre-fort.</string>
|
||||
<string name="authentication_method_fingerprint">Empreinte digitale</string>
|
||||
<string name="authentication_method_fingerprint_description">En plus d\'un mot de passe, les empreintes digitales enregistrées sur cet appareil peuvent être utilisées pour déverrouiller le coffre-fort.</string>
|
||||
<string name="authentication_method_set_password">Mot de passe</string>
|
||||
<string name="authentication_enter_password">Saisissez votre mot de passe</string>
|
||||
<string name="authentication">Déverrouiller le coffre-fort</string>
|
||||
|
@ -64,7 +56,6 @@
|
|||
<string name="set_group">Veuillez saisir un nom de groupe</string>
|
||||
<string name="set_number">Veuillez saisir un nombre</string>
|
||||
<string name="set_password_confirm">Veuillez confirmer le mot de passe</string>
|
||||
<string name="invalidated_fingerprint">Un changement dans les paramètres de sécurité de votre appareil a été détecté. Veuillez aller dans \"Aegis -> Paramètres -> Empreinte digitale\" et ajouter à nouveau votre empreinte digitale.</string>
|
||||
|
||||
<string name="unlock">Déverrouiller</string>
|
||||
<string name="advanced">Avancé</string>
|
||||
|
@ -75,7 +66,6 @@
|
|||
<string name="scan">Scanner code QR</string>
|
||||
<string name="scan_image">Scanner image</string>
|
||||
<string name="enter_manually">Saisir manuellement</string>
|
||||
<string name="add_fingerprint">Ajouter une empreinte digitale</string>
|
||||
<string name="add_password">Ajouter un mot de passe</string>
|
||||
<string name="slots_warning">Le coffre-fort est seulement aussi sécurisé que votre code secret le plus faible. Quand une nouvelle empreinte digitale est ajoutée à votre appareil, vous devrez réactiver l\'authentification par empreinte digitale dans Aegis.</string>
|
||||
<string name="copy">Copier</string>
|
||||
|
@ -88,7 +78,6 @@
|
|||
<string name="unlock_vault_error">Impossible de déverrouiller le coffre-fort</string>
|
||||
<string name="unlock_vault_error_description">Mot de passe incorrect. Assurez-vous de ne pas avoir fait de faute de frappe lors de la saisie de votre mot de passe.</string>
|
||||
<string name="password_equality_error">Les mots de passe doivent être identiques et non vides</string>
|
||||
<string name="register_fingerprint">Enregistrer votre empreinte digitale</string>
|
||||
<string name="snackbar_authentication_method">Veuillez sélectionner une méthode d\'authentification</string>
|
||||
<string name="encrypting_vault">Chiffrement du coffre-fort</string>
|
||||
<string name="delete_entry">Supprimer entrée</string>
|
||||
|
@ -127,7 +116,6 @@
|
|||
<string name="export_database_location">La base de données a été exportée vers :</string>
|
||||
<string name="export_warning">Cette action va exporter la base de données en dehors du stockage privé d\'Aegis.</string>
|
||||
<string name="encryption_set_password_error">Une erreur est survenue en essayant de définir le mot de passe : </string>
|
||||
<string name="encryption_enable_fingerprint_error">Une erreur est survenue en essayant d\'activer le déverrouillage par empreinte digitale : </string>
|
||||
<string name="no_cameras_available">Aucun appareil photo disponible</string>
|
||||
<string name="read_qr_error">Une erreur est survenue en essayant de lire le code QR</string>
|
||||
<string name="authentication_method_raw">Brut</string>
|
||||
|
|
|
@ -36,22 +36,14 @@
|
|||
<string name="pref_tap_to_reveal_time_title">Time-out voor drukken om te laten zien</string>
|
||||
<string name="pref_encryption_title">Encryptie</string>
|
||||
<string name="pref_encryption_summary">Encrypt de database en ontgrendel deze met een wachtwoord of vingerafdruk</string>
|
||||
<string name="pref_fingerprint_title">Vingerafdruk</string>
|
||||
<string name="pref_fingerprint_summary">Schakel in om met de op dit toestel geregistreerde vingerafdrukken de kluis te kunnen ontgrendelen</string>
|
||||
<string name="pref_set_password_title">Wachtwoord wijzigen</string>
|
||||
<string name="pref_set_password_summary">Stel een nieuw wachtwoord in waarmee je de kluis kunt ontgrendelen</string>
|
||||
|
||||
<string name="fingerprint_hint">Aanraaksensor</string>
|
||||
<string name="fingerprint_not_recognized">Vingerafdruk niet herkend. Probeer opnieuw.</string>
|
||||
<string name="fingerprint_success">Vingerafdruk herkend</string>
|
||||
|
||||
<string name="choose_authentication_method">Beveiliging</string>
|
||||
<string name="authentication_method_none">Geen</string>
|
||||
<string name="authentication_method_none_description">Je hebt geen wachtwoord nodig om de kluis te ontgrendelen en de kluis zal niet worden geëncrypt. Deze optie wordt niet aanbevolen.</string>
|
||||
<string name="authentication_method_password">Wachtwoord</string>
|
||||
<string name="authentication_method_password_description">Je hebt een wachtwoord nodig om de kluis te ontgrendelen.</string>
|
||||
<string name="authentication_method_fingerprint">Vingerafdruk</string>
|
||||
<string name="authentication_method_fingerprint_description">Als toevoeging op een wachtwoord kan er ook gebruik gemaakt worden van de op dit toestel geregistreerde vingerafdrukken om de kluis te ontgrendelen.</string>
|
||||
<string name="authentication_method_set_password">Wachtwoord</string>
|
||||
<string name="authentication_enter_password">Vul je wachtwoord in</string>
|
||||
<string name="authentication">Kluis ontgrendelen</string>
|
||||
|
@ -59,7 +51,6 @@
|
|||
<string name="set_group">Vul een groepsnaam in</string>
|
||||
<string name="set_number">Kies een getal</string>
|
||||
<string name="set_password_confirm">Bevestig het wachtwoord</string>
|
||||
<string name="invalidated_fingerprint">Er is een verandering in de beveiligingsinstellingen van je toestel gedetecteerd. Ga naar \"Instellingen -> Vingerafdruk\" om je vingerafdruk opnieuw toe te voegen.</string>
|
||||
|
||||
<string name="unlock">Ontgrendel</string>
|
||||
<string name="advanced">Geavanceerd</string>
|
||||
|
@ -69,7 +60,6 @@
|
|||
<string name="secret">Sleutel</string>
|
||||
<string name="scan">Scan QR-code</string>
|
||||
<string name="enter_manually">Handmatig invoeren</string>
|
||||
<string name="add_fingerprint">Vingerafdruk toevoegen</string>
|
||||
<string name="add_password">Wachtwoord toevoegen</string>
|
||||
<string name="slots_warning">De kluis is slechts even veilig als je zwakste wachtwoord. Wanneer een nieuw vingerafdruk is toegevoegd aan je toestel, moet authenticatie met vingerafdruk opnieuw worden geactiveerd binnen Aegis.</string>
|
||||
<string name="copy">Kopiëren</string>
|
||||
|
@ -82,7 +72,6 @@
|
|||
<string name="unlock_vault_error">Kluis kon niet worden ontgrendeld</string>
|
||||
<string name="unlock_vault_error_description">Wachtwoord onjuist. Controleer of je het wachtwoord correct hebt ingetypt.</string>
|
||||
<string name="password_equality_error">Wachtwoorden moeten overeen komen en mogen niet leeg zijn</string>
|
||||
<string name="register_fingerprint">Registreer je vingerafdruk</string>
|
||||
<string name="snackbar_authentication_method">Kies een inlogmethode</string>
|
||||
<string name="encrypting_vault">De kluis wordt geëncrypt</string>
|
||||
<string name="delete_entry">Item verwijderen</string>
|
||||
|
@ -117,7 +106,6 @@
|
|||
<string name="export_database_location">De database is geëxporteerd naar:</string>
|
||||
<string name="export_warning">Deze actie zal de database uit de privé-opslag van Aegis exporteren.</string>
|
||||
<string name="encryption_set_password_error">Er is een fout opgetreden tijdens het instellen van het wachtwoord: </string>
|
||||
<string name="encryption_enable_fingerprint_error">Er is een fout opgetreden tijdens het inschakelen van ontgrendeling met vingerafdruk: </string>
|
||||
<string name="no_cameras_available">Geen camera\'s beschikbaar</string>
|
||||
<string name="read_qr_error">Er is een fout opgetreden tijdens het lezen van de QR-code</string>
|
||||
<string name="authentication_method_raw">Onbewerkt</string>
|
||||
|
|
|
@ -36,22 +36,14 @@
|
|||
<string name="pref_auto_lock_summary">Автоматическая блокировка при закрытии приложения и блокировке устройства.</string>
|
||||
<string name="pref_encryption_title">Шифрование</string>
|
||||
<string name="pref_encryption_summary">Зашифруйте базу данных и разблокируйте ее с помощью пароля или отпечатка пальца</string>
|
||||
<string name="pref_fingerprint_title">Отпечаток пальца</string>
|
||||
<string name="pref_fingerprint_summary">Разрешить разблокировку хранилища при помощи отпечатков пальцев, зарегистрированных на этом устройстве</string>
|
||||
<string name="pref_set_password_title">Изменить пароль</string>
|
||||
<string name="pref_set_password_summary">Установите новый пароль, который вам понадобится, чтобы разблокировать ваше хранилище</string>
|
||||
|
||||
<string name="fingerprint_hint">Прикоснитесь к сенсору</string>
|
||||
<string name="fingerprint_not_recognized">Отпечаток пальца не распознан. Попробуйте снова.</string>
|
||||
<string name="fingerprint_success">Отпечаток пальца распознан</string>
|
||||
|
||||
<string name="choose_authentication_method">Безопасность</string>
|
||||
<string name="authentication_method_none">Нет</string>
|
||||
<string name="authentication_method_none_description">Вам не нужен пароль для разблокировки хранилища, и оно не будет зашифровано. Этот вариант не рекомендуется.</string>
|
||||
<string name="authentication_method_password">Пароль</string>
|
||||
<string name="authentication_method_password_description">Вам нужен пароль, чтобы разблокировать хранилище.</string>
|
||||
<string name="authentication_method_fingerprint">Отпечаток пальца</string>
|
||||
<string name="authentication_method_fingerprint_description">В дополнение к паролю, для разблокировки хранилища можно использовать отпечатки пальцев, зарегистрированные на этом устройстве.</string>
|
||||
<string name="authentication_method_set_password">Пароль</string>
|
||||
<string name="authentication_enter_password">Введите свой пароль</string>
|
||||
<string name="authentication">Разблокировать хранилище</string>
|
||||
|
@ -59,7 +51,6 @@
|
|||
<string name="set_group">Пожалуйста, введите название группы</string>
|
||||
<string name="set_number">Пожалуйста, введите номер</string>
|
||||
<string name="set_password_confirm">Пожалуйста, подтвердите пароль</string>
|
||||
<string name="invalidated_fingerprint">Обнаружено изменение настроек безопасности вашего устройства. Перейдите в «Настройки - Отпечаток пальца» и повторно добавьте свой отпечаток пальца.</string>
|
||||
|
||||
<string name="unlock">Разблокировать</string>
|
||||
<string name="advanced">Расширенные</string>
|
||||
|
@ -70,7 +61,6 @@
|
|||
<string name="scan">Сканировать QR-код</string>
|
||||
<string name="scan_image">Сканировать изображение</string>
|
||||
<string name="enter_manually">Ввести вручную</string>
|
||||
<string name="add_fingerprint">Добавить отпечаток</string>
|
||||
<string name="add_password">Добавить пароль</string>
|
||||
<string name="slots_warning">Хранилище надежно защищено. При добавлении нового отпечатка пальца на ваше устройство необходимо будет заново настроить разблокировку хранилища по отпечатку пальца в Aegis.</string>
|
||||
<string name="copy">Копировать</string>
|
||||
|
@ -83,7 +73,6 @@
|
|||
<string name="unlock_vault_error">Не удалось разблокировать хранилище</string>
|
||||
<string name="unlock_vault_error_description">Некорректный пароль. Убедитесь, что вы не допустили опечатку в вашем пароле.</string>
|
||||
<string name="password_equality_error">Пароли должны быть одинаковыми и непустыми</string>
|
||||
<string name="register_fingerprint">Зарегистрируйте свой отпечаток пальца</string>
|
||||
<string name="snackbar_authentication_method">Пожалуйста, выберите метод аутентификации</string>
|
||||
<string name="encrypting_vault">Шифрование хранилища</string>
|
||||
<string name="delete_entry">Удалить запись</string>
|
||||
|
@ -122,7 +111,6 @@
|
|||
<string name="export_database_location">База данных была экспортирована в:</string>
|
||||
<string name="export_warning">Это действие экспортирует базу данных из приватного хранилища Aegis.</string>
|
||||
<string name="encryption_set_password_error">Произошла ошибка при попытке установить пароль:</string>
|
||||
<string name="encryption_enable_fingerprint_error">Произошла ошибка при попытке разблокировать отпечаток пальца:</string>
|
||||
<string name="no_cameras_available">Нет доступных камер</string>
|
||||
<string name="read_qr_error">Произошла ошибка при попытке прочитать QR-код</string>
|
||||
<string name="authentication_method_raw">Необработанный</string>
|
||||
|
|
|
@ -40,20 +40,13 @@
|
|||
<string name="pref_auto_lock_summary">关闭应用或锁定设备时自动锁定</string>
|
||||
<string name="pref_encryption_title">加密</string>
|
||||
<string name="pref_encryption_summary">加密数据库并使用密码或指纹解锁数据库</string>
|
||||
<string name="pref_fingerprint_title">指纹</string>
|
||||
<string name="pref_fingerprint_summary">允许在此设备上注册的指纹解锁数据库</string>
|
||||
<string name="pref_set_password_title">更改密码</string>
|
||||
<string name="pref_set_password_summary">设置解锁数据库所需的新密码</string>
|
||||
<string name="fingerprint_hint">触摸感应器</string>
|
||||
<string name="fingerprint_not_recognized">无法识别指纹。再试一次。</string>
|
||||
<string name="fingerprint_success">识别指纹</string>
|
||||
<string name="choose_authentication_method">安全</string>
|
||||
<string name="authentication_method_none">未设置</string>
|
||||
<string name="authentication_method_none_description">您无需密码即可解锁保管库,也不会对其进行加密。不建议使用此选项。</string>
|
||||
<string name="authentication_method_password">密码</string>
|
||||
<string name="authentication_method_password_description">您需要密码来解锁数据库。</string>
|
||||
<string name="authentication_method_fingerprint">指纹</string>
|
||||
<string name="authentication_method_fingerprint_description">除了密码之外,在此设备上注册的指纹也可用于解锁数据库。</string>
|
||||
<string name="authentication_method_set_password">密码</string>
|
||||
<string name="authentication_enter_password">输入您的密码</string>
|
||||
<string name="authentication">打开数据库</string>
|
||||
|
@ -61,7 +54,6 @@
|
|||
<string name="set_group">请输入组名</string>
|
||||
<string name="set_number">请输入号码</string>
|
||||
<string name="set_password_confirm">请确认密码</string>
|
||||
<string name="invalidated_fingerprint">检测到设备安全设置更改。请到“Aegis- >设置- >指纹”,重新添加您的指纹。</string>
|
||||
<string name="unlock">解锁</string>
|
||||
<string name="advanced">高级设置</string>
|
||||
<string name="seconds">秒</string>
|
||||
|
@ -71,7 +63,6 @@
|
|||
<string name="scan">扫描二维码</string>
|
||||
<string name="scan_image">扫描图像</string>
|
||||
<string name="enter_manually">手动输入</string>
|
||||
<string name="add_fingerprint">添加指纹</string>
|
||||
<string name="add_password">添加密码</string>
|
||||
<string name="slots_warning">数据库与您最薄弱的秘密一样安全。向设备添加新指纹时,您需要在 Aegis 中重新激活指纹身份验证。</string>
|
||||
<string name="copy">复制</string>
|
||||
|
@ -84,7 +75,6 @@
|
|||
<string name="unlock_vault_error">无法解锁数据库</string>
|
||||
<string name="unlock_vault_error_description">密码错误。确保您未输错密码。</string>
|
||||
<string name="password_equality_error">密码应该是相同且非空的。</string>
|
||||
<string name="register_fingerprint">注册您的指纹</string>
|
||||
<string name="snackbar_authentication_method">请选择身份验证方法</string>
|
||||
<string name="encrypting_vault">加密数据库</string>
|
||||
<string name="delete_entry">删除条目</string>
|
||||
|
@ -123,7 +113,6 @@
|
|||
<string name="export_database_location">数据库已经导出至:</string>
|
||||
<string name="export_warning">此操作将导出 Aegis 专用存储的数据库。</string>
|
||||
<string name="encryption_set_password_error">试图设置密码时出错:</string>
|
||||
<string name="encryption_enable_fingerprint_error">试图启用指纹解锁时出错:</string>
|
||||
<string name="no_cameras_available">未找到可用的相机</string>
|
||||
<string name="read_qr_error">试图读取二维码时出错</string>
|
||||
<string name="authentication_method_raw">源文件</string>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<string-array name="authentication_methods">
|
||||
<item>@string/authentication_method_none</item>
|
||||
<item>@string/authentication_method_password</item>
|
||||
<item>@string/authentication_method_fingerprint</item>
|
||||
<item>@string/authentication_method_biometrics</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="otp_types_array">
|
||||
|
|
|
@ -19,11 +19,6 @@
|
|||
<color name="card_background">#ffffff</color>
|
||||
<color name="card_background_focused">#DBDBDB</color>
|
||||
|
||||
<color name="colorSwirlPrimary">#434343</color>
|
||||
<color name="colorSwirlError">#FF5252</color>
|
||||
<color name="colorSwirlPrimaryDark">#FFFFFF</color>
|
||||
<color name="colorSwirlErrorDark">#FF5252</color>
|
||||
|
||||
<color name="icon_primary">#757575</color>
|
||||
<color name="icon_primary_inverted">#ffffff</color>
|
||||
<color name="icon_primary_dark">#ffffff</color>
|
||||
|
|
|
@ -40,23 +40,19 @@
|
|||
<string name="pref_auto_lock_title">Auto lock</string>
|
||||
<string name="pref_auto_lock_summary">Automatically lock when you close the app or lock your device.</string>
|
||||
<string name="pref_encryption_title">Encryption</string>
|
||||
<string name="pref_encryption_summary">Encrypt the database and unlock it with a password or fingerprint</string>
|
||||
<string name="pref_fingerprint_title">Fingerprint</string>
|
||||
<string name="pref_fingerprint_summary">Allow fingerprints registered on this device to unlock the vault</string>
|
||||
<string name="pref_encryption_summary">Encrypt the database and unlock it with a password or biometrics</string>
|
||||
<string name="pref_biometrics_title">Biometric unlock</string>
|
||||
<string name="pref_biometrics_summary">Allow biometric authentication to unlock the vault</string>
|
||||
<string name="pref_set_password_title">Change password</string>
|
||||
<string name="pref_set_password_summary">Set a new password which you will need to unlock your vault</string>
|
||||
|
||||
<string name="fingerprint_hint">Touch sensor</string>
|
||||
<string name="fingerprint_not_recognized">Fingerprint not recognized. Try again.</string>
|
||||
<string name="fingerprint_success">Fingerprint recognized</string>
|
||||
|
||||
<string name="choose_authentication_method">Security</string>
|
||||
<string name="authentication_method_none">None</string>
|
||||
<string name="authentication_method_none_description">You don\'t need a password to unlock the vault and it will not be encrypted. This option is not recommended.</string>
|
||||
<string name="authentication_method_password">Password</string>
|
||||
<string name="authentication_method_password_description">You need a password to unlock the vault.</string>
|
||||
<string name="authentication_method_fingerprint">Fingerprint</string>
|
||||
<string name="authentication_method_fingerprint_description">In addition to a password, fingerprints registered on this device can be used to unlock the vault.</string>
|
||||
<string name="authentication_method_biometrics">Biometrics</string>
|
||||
<string name="authentication_method_biometrics_description">In addition to a password, biometrics registered on this device, like a fingerprint or your face, can be used to unlock the vault.</string>
|
||||
<string name="authentication_method_set_password">Password</string>
|
||||
<string name="authentication_enter_password">Enter your password</string>
|
||||
<string name="authentication">Unlock the vault</string>
|
||||
|
@ -64,9 +60,10 @@
|
|||
<string name="set_group">Please enter a group name</string>
|
||||
<string name="set_number">Please enter a number</string>
|
||||
<string name="set_password_confirm">Please confirm the password</string>
|
||||
<string name="invalidated_fingerprint">A change in your device\'s security settings has been detected. Please go to \"Aegis -> Settings -> Fingerprint\" and re-add your fingerprint.</string>
|
||||
<string name="invalidated_biometrics">A change in your device\'s security settings has been detected. Please go to \"Aegis -> Settings -> Biometrics\" and re-enable biometric unlock.</string>
|
||||
|
||||
<string name="unlock">Unlock</string>
|
||||
<string name="biometrics">Biometrics</string>
|
||||
<string name="advanced">Advanced</string>
|
||||
<string name="seconds">seconds</string>
|
||||
<string name="counter">Counter</string>
|
||||
|
@ -75,9 +72,11 @@
|
|||
<string name="scan">Scan QR code</string>
|
||||
<string name="scan_image">Scan image</string>
|
||||
<string name="enter_manually">Enter manually</string>
|
||||
<string name="add_fingerprint">Add fingerprint</string>
|
||||
<string name="add_biometric">Add biometric</string>
|
||||
<string name="add_biometric_slot">Add biometric slot</string>
|
||||
<string name="set_up_biometric">Set up biometric unlock</string>
|
||||
<string name="add_password">Add password</string>
|
||||
<string name="slots_warning">The vault is only as secure as your weakest secret. When a new fingerprint is added to your device, you will need to reactivate fingerprint authentication within Aegis.</string>
|
||||
<string name="slots_warning">The vault is only as secure as your weakest secret. If you change the biometric authentication settings of your device, you will need to reactivate biometric unlock within Aegis.</string>
|
||||
<string name="copy">Copy</string>
|
||||
<string name="edit">Edit</string>
|
||||
<string name="delete">Delete</string>
|
||||
|
@ -89,7 +88,6 @@
|
|||
<string name="unlock_vault_error">Couldn\'t unlock vault</string>
|
||||
<string name="unlock_vault_error_description">Incorrect password. Make sure you didn\'t mistype your password.</string>
|
||||
<string name="password_equality_error">Passwords should be identical and non-empty</string>
|
||||
<string name="register_fingerprint">Register your fingerprint</string>
|
||||
<string name="snackbar_authentication_method">Please select an authentication method</string>
|
||||
<string name="encrypting_vault">Encrypting the vault</string>
|
||||
<string name="delete_entry">Delete entry</string>
|
||||
|
@ -132,7 +130,7 @@
|
|||
<string name="export_database_location">The database has been exported to:</string>
|
||||
<string name="export_warning">This action will export the database out of Aegis\' private storage.</string>
|
||||
<string name="encryption_set_password_error">An error occurred while trying to set the password: </string>
|
||||
<string name="encryption_enable_fingerprint_error">An error occurred while trying to enable fingerprint unlock: </string>
|
||||
<string name="encryption_enable_biometrics_error">An error occurred while trying to enable biometric unlock</string>
|
||||
<string name="no_cameras_available">No cameras available</string>
|
||||
<string name="read_qr_error">An error occurred while trying to read the QR code</string>
|
||||
<string name="authentication_method_raw">Raw</string>
|
||||
|
|
|
@ -11,8 +11,6 @@
|
|||
</style>
|
||||
|
||||
<style name="Theme.Intro" parent="Theme.AppCompat.NoActionBar">
|
||||
<item name="swirl_ridgeColor">@color/primary_text_inverted</item>
|
||||
<item name="swirl_errorColor">@color/colorSwirlError</item>
|
||||
<item name="android:windowBackground">@android:color/transparent</item>
|
||||
<item name="android:windowIsTranslucent">true</item>
|
||||
</style>
|
||||
|
@ -35,9 +33,6 @@
|
|||
<item name="iconColorPrimary">@color/icon_primary</item>
|
||||
<item name="iconColorInverted">@color/icon_primary_inverted</item>
|
||||
|
||||
<item name="swirl_ridgeColor">@color/colorSwirlPrimary</item>
|
||||
<item name="swirl_errorColor">@color/colorSwirlError</item>
|
||||
|
||||
<item name="actionModeStyle">@style/ActionModeStyle</item>
|
||||
<item name="actionBarTheme">@style/ThemeOverlay.AppCompat.Dark.ActionBar</item>
|
||||
<item name="alertDialogTheme">@style/DialogStyle</item>
|
||||
|
@ -104,9 +99,6 @@
|
|||
<item name="iconColorPrimary">@color/icon_primary_dark</item>
|
||||
<item name="iconColorInverted">@color/icon_primary_dark_inverted</item>
|
||||
|
||||
<item name="swirl_ridgeColor">@color/colorSwirlPrimaryDark</item>
|
||||
<item name="swirl_errorColor">@color/colorSwirlErrorDark</item>
|
||||
|
||||
<item name="actionModeStyle">@style/ActionModeStyle.Dark</item>
|
||||
<item name="alertDialogTheme">@style/DialogStyle.Dark</item>
|
||||
|
||||
|
|
|
@ -103,9 +103,9 @@
|
|||
app:iconSpaceReserved="false"/>
|
||||
|
||||
<com.beemdevelopment.aegis.ui.preferences.SwitchPreference
|
||||
android:key="pref_fingerprint"
|
||||
android:title="@string/pref_fingerprint_title"
|
||||
android:summary="@string/pref_fingerprint_summary"
|
||||
android:key="pref_biometrics"
|
||||
android:title="@string/pref_biometrics_title"
|
||||
android:summary="@string/pref_biometrics_summary"
|
||||
android:persistent="false"
|
||||
app:iconSpaceReserved="false"/>
|
||||
|
||||
|
|
File diff suppressed because one or more lines are too long
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
|
@ -70,8 +70,8 @@ __master key__.
|
|||
|
||||
Aegis supports unlocking a vault with multiple different credentials. The main
|
||||
credential is a key derived from a user-provided password. In addition to that,
|
||||
users can also add a key backed by the Android KeyStore (authorized by the scan
|
||||
of a fingerprint) as a credential.
|
||||
users can also add a key backed by the Android KeyStore (authorized by biometrics)
|
||||
as a credential.
|
||||
|
||||
#### Slots
|
||||
|
||||
|
@ -146,7 +146,7 @@ The different slot types are identified with a numerical ID.
|
|||
| Type | ID |
|
||||
| :---------- | :--- |
|
||||
| Raw | 0x00 |
|
||||
| Fingerprint | 0x01 |
|
||||
| Biometric | 0x01 |
|
||||
| Password | 0x02 |
|
||||
|
||||
##### Raw
|
||||
|
@ -172,9 +172,9 @@ a unique randomly generated ``UUID`` (version 4).
|
|||
}
|
||||
```
|
||||
|
||||
##### Fingerprint
|
||||
##### Biometric
|
||||
|
||||
The structure of the Fingerprint slot is exactly the same as the Raw slot. The
|
||||
The structure of the Biometric slot is exactly the same as the Raw slot. The
|
||||
difference is that the wrapper key is backed by the Android KeyStore, whereas
|
||||
Raw slots don't imply use of a particular storage type.
|
||||
|
||||
|
|
|
@ -7,10 +7,10 @@ to set a password, which is highly recommended, the vault will be encrypted
|
|||
using AES-256. If someone with malicious intent gets a hold of the vault file,
|
||||
it’s impossible for them to retrieve the contents without knowing the password.
|
||||
|
||||
<b>Fingerprint unlock</b>
|
||||
<b>Biometric unlock</b>
|
||||
Entering your password each time you need access to a
|
||||
one-time password can be cumbersome. Fortunately, you can also enable
|
||||
fingerprint unlock if your device has a fingerprint scanner.
|
||||
biometric unlock if your device has a biometrics sensor.
|
||||
|
||||
<b>Compatibility</b>
|
||||
Aegis supports the HOTP and TOTP algorithms. These two algorithms are
|
||||
|
|
Loading…
Add table
Reference in a new issue