2019-02-07 22:39:33 +01:00
|
|
|
package com.beemdevelopment.aegis.ui;
|
2017-08-06 18:15:47 +02:00
|
|
|
|
|
|
|
import android.content.Intent;
|
2017-08-13 23:38:38 +02:00
|
|
|
import android.hardware.fingerprint.FingerprintManager;
|
2017-12-26 13:38:57 +01:00
|
|
|
import android.os.Build;
|
2017-08-06 18:15:47 +02:00
|
|
|
import android.os.Bundle;
|
2018-09-19 00:20:39 +02:00
|
|
|
import android.view.KeyEvent;
|
2017-08-06 18:15:47 +02:00
|
|
|
import android.view.View;
|
2017-12-26 13:38:57 +01:00
|
|
|
import android.view.ViewGroup;
|
2019-04-14 00:38:19 +02:00
|
|
|
import android.view.WindowManager;
|
2018-09-19 00:20:39 +02:00
|
|
|
import android.view.inputmethod.EditorInfo;
|
2017-08-06 18:15:47 +02:00
|
|
|
import android.widget.Button;
|
|
|
|
import android.widget.EditText;
|
2017-08-13 23:38:38 +02:00
|
|
|
import android.widget.LinearLayout;
|
|
|
|
import android.widget.TextView;
|
2017-08-06 18:15:47 +02:00
|
|
|
|
2019-04-04 14:07:36 +02:00
|
|
|
import com.beemdevelopment.aegis.R;
|
2019-02-07 22:39:33 +01:00
|
|
|
import com.beemdevelopment.aegis.crypto.KeyStoreHandle;
|
|
|
|
import com.beemdevelopment.aegis.crypto.KeyStoreHandleException;
|
|
|
|
import com.beemdevelopment.aegis.crypto.MasterKey;
|
|
|
|
import com.beemdevelopment.aegis.db.DatabaseFileCredentials;
|
2019-04-04 14:07:36 +02:00
|
|
|
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.db.slots.SlotList;
|
2019-02-07 22:39:33 +01:00
|
|
|
import com.beemdevelopment.aegis.helpers.EditTextHelper;
|
|
|
|
import com.beemdevelopment.aegis.helpers.FingerprintHelper;
|
|
|
|
import com.beemdevelopment.aegis.helpers.FingerprintUiHelper;
|
|
|
|
import com.beemdevelopment.aegis.ui.tasks.SlotListTask;
|
2017-08-19 16:48:57 +02:00
|
|
|
import com.mattprecious.swirl.SwirlView;
|
|
|
|
|
2017-08-06 18:15:47 +02:00
|
|
|
import javax.crypto.Cipher;
|
|
|
|
import javax.crypto.SecretKey;
|
|
|
|
|
2019-04-04 14:07:36 +02:00
|
|
|
import androidx.appcompat.app.AlertDialog;
|
2017-08-06 18:15:47 +02:00
|
|
|
|
2018-06-06 21:30:24 +02:00
|
|
|
public class AuthActivity extends AegisActivity implements FingerprintUiHelper.Callback, SlotListTask.Callback {
|
2017-08-26 21:15:53 +02:00
|
|
|
private EditText _textPassword;
|
2017-08-06 18:15:47 +02:00
|
|
|
|
2018-06-06 19:38:13 +02:00
|
|
|
private SlotList _slots;
|
2017-08-26 21:15:53 +02:00
|
|
|
private FingerprintUiHelper _fingerHelper;
|
2019-04-04 18:09:59 +02:00
|
|
|
private FingerprintManager.CryptoObject _fingerCryptoObj;
|
2017-08-13 23:38:38 +02:00
|
|
|
|
2017-08-06 18:15:47 +02:00
|
|
|
@Override
|
|
|
|
protected void onCreate(Bundle savedInstanceState) {
|
|
|
|
super.onCreate(savedInstanceState);
|
|
|
|
setContentView(R.layout.activity_auth);
|
2017-12-12 02:21:13 +01:00
|
|
|
_textPassword = findViewById(R.id.text_password);
|
|
|
|
LinearLayout boxFingerprint = findViewById(R.id.box_fingerprint);
|
2018-02-13 13:25:13 +01:00
|
|
|
LinearLayout boxFingerprintInfo = findViewById(R.id.box_fingerprint_info);
|
2017-12-12 02:21:13 +01:00
|
|
|
TextView textFingerprint = findViewById(R.id.text_fingerprint);
|
2018-09-19 00:20:39 +02:00
|
|
|
Button decryptButton = findViewById(R.id.button_decrypt);
|
|
|
|
|
|
|
|
_textPassword.setOnEditorActionListener((v, actionId, event) -> {
|
|
|
|
if ((event != null && (event.getKeyCode() == KeyEvent.KEYCODE_ENTER)) || (actionId == EditorInfo.IME_ACTION_DONE)) {
|
|
|
|
decryptButton.performClick();
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
});
|
2017-08-06 18:15:47 +02:00
|
|
|
|
2017-12-26 13:38:57 +01:00
|
|
|
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));
|
|
|
|
}
|
|
|
|
|
2017-08-06 18:15:47 +02:00
|
|
|
Intent intent = getIntent();
|
2018-06-06 19:38:13 +02:00
|
|
|
_slots = (SlotList) intent.getSerializableExtra("slots");
|
2017-08-13 23:38:38 +02:00
|
|
|
|
|
|
|
// 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
|
2017-12-26 13:25:21 +01:00
|
|
|
FingerprintManager manager = FingerprintHelper.getManager(this);
|
2017-12-23 18:26:57 +01:00
|
|
|
if (manager != null && _slots.has(FingerprintSlot.class)) {
|
2018-02-13 13:25:13 +01:00
|
|
|
boolean invalidated = false;
|
2017-12-23 18:26:57 +01:00
|
|
|
try {
|
2018-02-10 17:20:41 +01:00
|
|
|
// find a fingerprint slot with an id that matches an alias in the keystore
|
|
|
|
for (FingerprintSlot slot : _slots.findAll(FingerprintSlot.class)) {
|
2018-03-13 18:30:47 +01:00
|
|
|
String id = slot.getUUID().toString();
|
2018-02-10 17:20:41 +01:00
|
|
|
KeyStoreHandle handle = new KeyStoreHandle();
|
|
|
|
if (handle.containsKey(id)) {
|
|
|
|
SecretKey key = handle.getKey(id);
|
2018-02-13 13:25:13 +01:00
|
|
|
// if 'key' is null, it was permanently invalidated
|
|
|
|
if (key == null) {
|
|
|
|
invalidated = true;
|
|
|
|
continue;
|
|
|
|
}
|
2019-04-04 18:09:59 +02:00
|
|
|
Cipher cipher = slot.createDecryptCipher(key);
|
|
|
|
_fingerCryptoObj = new FingerprintManager.CryptoObject(cipher);
|
2018-02-10 17:20:41 +01:00
|
|
|
_fingerHelper = new FingerprintUiHelper(manager, imgFingerprint, textFingerprint, this);
|
|
|
|
boxFingerprint.setVisibility(View.VISIBLE);
|
2018-02-13 13:25:13 +01:00
|
|
|
invalidated = false;
|
2018-02-10 17:20:41 +01:00
|
|
|
break;
|
|
|
|
}
|
2017-08-13 23:38:38 +02:00
|
|
|
}
|
2018-03-19 18:00:53 +01:00
|
|
|
} catch (KeyStoreHandleException | SlotException e) {
|
2019-04-04 14:07:36 +02:00
|
|
|
throw new RuntimeException(e);
|
2017-08-13 23:38:38 +02:00
|
|
|
}
|
2018-02-13 13:25:13 +01:00
|
|
|
|
|
|
|
// display a help message if a matching invalidated keystore entry was found
|
|
|
|
if (invalidated) {
|
|
|
|
boxFingerprintInfo.setVisibility(View.VISIBLE);
|
|
|
|
}
|
2017-08-13 23:38:38 +02:00
|
|
|
}
|
2017-08-06 18:15:47 +02:00
|
|
|
|
2018-09-19 00:20:39 +02:00
|
|
|
decryptButton.setOnClickListener(new View.OnClickListener() {
|
2017-08-06 18:15:47 +02:00
|
|
|
@Override
|
|
|
|
public void onClick(View v) {
|
2018-02-13 21:17:21 +01:00
|
|
|
char[] password = EditTextHelper.getEditTextChars(_textPassword);
|
2017-11-27 18:24:55 +01:00
|
|
|
trySlots(PasswordSlot.class, password);
|
2017-08-06 18:15:47 +02:00
|
|
|
}
|
|
|
|
});
|
2019-04-14 00:38:19 +02:00
|
|
|
|
|
|
|
if (_fingerHelper == null) {
|
|
|
|
_textPassword.requestFocus();
|
|
|
|
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
|
|
|
|
}
|
2017-08-06 18:15:47 +02:00
|
|
|
}
|
|
|
|
|
2017-08-19 13:50:33 +02:00
|
|
|
private void showError() {
|
2018-11-15 22:20:31 +01:00
|
|
|
Dialogs.showSecureDialog(new AlertDialog.Builder(this)
|
|
|
|
.setTitle(getString(R.string.unlock_vault_error))
|
|
|
|
.setMessage(getString(R.string.unlock_vault_error_description))
|
|
|
|
.setCancelable(false)
|
|
|
|
.setPositiveButton(android.R.string.ok, null)
|
|
|
|
.create());
|
2017-08-19 13:50:33 +02:00
|
|
|
}
|
|
|
|
|
2017-11-27 18:24:55 +01:00
|
|
|
private <T extends Slot> void trySlots(Class<T> type, Object obj) {
|
2018-06-06 21:30:24 +02:00
|
|
|
SlotListTask.Params params = new SlotListTask.Params(_slots, obj);
|
|
|
|
new SlotListTask<>(type, this, this).execute(params);
|
2017-08-19 13:50:33 +02:00
|
|
|
}
|
2017-08-18 22:12:45 +02:00
|
|
|
|
2017-08-19 13:50:33 +02:00
|
|
|
private void setKey(MasterKey key) {
|
2017-08-13 23:38:38 +02:00
|
|
|
// send the master key back to the main activity
|
|
|
|
Intent result = new Intent();
|
2018-10-06 22:23:38 +02:00
|
|
|
result.putExtra("creds", new DatabaseFileCredentials(key, _slots));
|
2017-08-13 23:38:38 +02:00
|
|
|
setResult(RESULT_OK, result);
|
|
|
|
finish();
|
|
|
|
}
|
|
|
|
|
2017-08-13 19:55:53 +02:00
|
|
|
@Override
|
|
|
|
public void onBackPressed() {
|
|
|
|
// ignore back button presses
|
|
|
|
}
|
|
|
|
|
2017-08-13 23:38:38 +02:00
|
|
|
@Override
|
|
|
|
public void onResume() {
|
|
|
|
super.onResume();
|
|
|
|
|
2017-08-26 21:15:53 +02:00
|
|
|
if (_fingerHelper != null) {
|
2019-04-04 18:09:59 +02:00
|
|
|
_fingerHelper.startListening(_fingerCryptoObj);
|
2017-08-13 23:38:38 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onPause() {
|
|
|
|
super.onPause();
|
|
|
|
|
2017-08-26 21:15:53 +02:00
|
|
|
if (_fingerHelper != null) {
|
|
|
|
_fingerHelper.stopListening();
|
2017-08-06 18:15:47 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-08-13 23:38:38 +02:00
|
|
|
@Override
|
|
|
|
public void onAuthenticated() {
|
2019-04-04 18:09:59 +02:00
|
|
|
trySlots(FingerprintSlot.class, _fingerCryptoObj.getCipher());
|
2017-08-13 23:38:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onError() {
|
|
|
|
|
2017-08-06 18:15:47 +02:00
|
|
|
}
|
2017-11-27 18:24:55 +01:00
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onTaskFinished(MasterKey key) {
|
|
|
|
if (key != null) {
|
|
|
|
setKey(key);
|
|
|
|
} else {
|
|
|
|
showError();
|
|
|
|
}
|
|
|
|
}
|
2017-08-06 18:15:47 +02:00
|
|
|
}
|