diff --git a/app/src/main/java/me/impy/aegis/AuthActivity.java b/app/src/main/java/me/impy/aegis/AuthActivity.java
index 2cf21f9a..1bde01ec 100644
--- a/app/src/main/java/me/impy/aegis/AuthActivity.java
+++ b/app/src/main/java/me/impy/aegis/AuthActivity.java
@@ -15,6 +15,7 @@ import android.widget.TextView;
import com.mattprecious.swirl.SwirlView;
import java.lang.reflect.UndeclaredThrowableException;
+import java.security.InvalidKeyException;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
@@ -30,9 +31,6 @@ import me.impy.aegis.helpers.FingerprintUiHelper;
import me.impy.aegis.helpers.AuthHelper;
public class AuthActivity extends AegisActivity implements FingerprintUiHelper.Callback, SlotCollectionTask.Callback {
- public static final int RESULT_OK = 0;
- public static final int RESULT_EXCEPTION = 1;
-
private EditText _textPassword;
private SlotCollection _slots;
@@ -45,6 +43,7 @@ public class AuthActivity extends AegisActivity implements FingerprintUiHelper.C
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);
SwirlView imgFingerprint = null;
@@ -60,6 +59,7 @@ public class AuthActivity extends AegisActivity implements FingerprintUiHelper.C
// 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
FingerprintManager manager = FingerprintHelper.getManager(this);
if (manager != null && _slots.has(FingerprintSlot.class)) {
+ boolean invalidated = false;
try {
// find a fingerprint slot with an id that matches an alias in the keystore
for (FingerprintSlot slot : _slots.findAll(FingerprintSlot.class)) {
@@ -67,15 +67,26 @@ public class AuthActivity extends AegisActivity implements FingerprintUiHelper.C
KeyStoreHandle handle = new KeyStoreHandle();
if (handle.containsKey(id)) {
SecretKey key = handle.getKey(id);
+ // if 'key' is null, it was permanently invalidated
+ if (key == null) {
+ invalidated = true;
+ continue;
+ }
_fingerCipher = Slot.createCipher(key, Cipher.DECRYPT_MODE);
_fingerHelper = new FingerprintUiHelper(manager, imgFingerprint, textFingerprint, this);
boxFingerprint.setVisibility(View.VISIBLE);
+ invalidated = false;
break;
}
}
} catch (Exception e) {
throw new UndeclaredThrowableException(e);
}
+
+ // display a help message if a matching invalidated keystore entry was found
+ if (invalidated) {
+ boxFingerprintInfo.setVisibility(View.VISIBLE);
+ }
}
Button button = findViewById(R.id.button_decrypt);
diff --git a/app/src/main/java/me/impy/aegis/SlotHolder.java b/app/src/main/java/me/impy/aegis/SlotHolder.java
index 46763565..55fe2cdf 100644
--- a/app/src/main/java/me/impy/aegis/SlotHolder.java
+++ b/app/src/main/java/me/impy/aegis/SlotHolder.java
@@ -6,6 +6,7 @@ import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
+import me.impy.aegis.crypto.KeyStoreHandle;
import me.impy.aegis.crypto.slots.FingerprintSlot;
import me.impy.aegis.crypto.slots.PasswordSlot;
import me.impy.aegis.crypto.slots.RawSlot;
@@ -29,13 +30,19 @@ public class SlotHolder extends RecyclerView.ViewHolder {
public void setData(Slot slot) {
if (slot instanceof PasswordSlot) {
- _slotName.setText("Password 1");
+ _slotName.setText("Password");
_slotImg.setImageResource(R.drawable.ic_create_black_24dp);
} else if (slot instanceof FingerprintSlot) {
- _slotName.setText("Finger 1");
+ _slotName.setText("Finger");
_slotImg.setImageResource(R.drawable.ic_fingerprint_black_24dp);
+ try {
+ KeyStoreHandle keyStore = new KeyStoreHandle();
+ if (keyStore.containsKey(slot.getID())) {
+ _slotUsed.setVisibility(View.VISIBLE);
+ }
+ } catch (Exception e) { }
} else if (slot instanceof RawSlot) {
- _slotName.setText("Raw 1");
+ _slotName.setText("Raw");
_slotImg.setImageResource(R.drawable.ic_vpn_key_black_24dp);
} else {
throw new RuntimeException();
diff --git a/app/src/main/java/me/impy/aegis/crypto/KeyStoreHandle.java b/app/src/main/java/me/impy/aegis/crypto/KeyStoreHandle.java
index 4488ca8c..7341ffc0 100644
--- a/app/src/main/java/me/impy/aegis/crypto/KeyStoreHandle.java
+++ b/app/src/main/java/me/impy/aegis/crypto/KeyStoreHandle.java
@@ -1,17 +1,22 @@
package me.impy.aegis.crypto;
+import android.annotation.SuppressLint;
import android.os.Build;
import android.security.keystore.KeyGenParameterSpec;
+import android.security.keystore.KeyPermanentlyInvalidatedException;
import android.security.keystore.KeyProperties;
import java.io.IOException;
+import java.security.InvalidKeyException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
+import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
+import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import me.impy.aegis.crypto.slots.FingerprintSlot;
@@ -47,7 +52,28 @@ public class KeyStoreHandle {
}
}
- public SecretKey getKey(String id) throws UnrecoverableKeyException, NoSuchAlgorithmException, KeyStoreException {
- return (SecretKey) _keyStore.getKey(id, null);
+ public SecretKey getKey(String id)
+ throws UnrecoverableKeyException, NoSuchAlgorithmException, KeyStoreException {
+ SecretKey key = (SecretKey) _keyStore.getKey(id, null);
+
+ // try to initialize a dummy cipher
+ // and see if KeyPermanentlyInvalidatedException is thrown
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ try {
+ @SuppressLint("GetInstance")
+ Cipher cipher = Cipher.getInstance(CryptoUtils.CRYPTO_CIPHER_RAW);
+ cipher.init(Cipher.ENCRYPT_MODE, key);
+ } catch (KeyPermanentlyInvalidatedException e) {
+ return null;
+ } catch (NoSuchPaddingException | InvalidKeyException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ return key;
+ }
+
+ public void deleteKey(String id) throws KeyStoreException {
+ _keyStore.deleteEntry(id);
}
}
diff --git a/app/src/main/res/layout/activity_auth.xml b/app/src/main/res/layout/activity_auth.xml
index c2e0e3af..35ead88e 100644
--- a/app/src/main/res/layout/activity_auth.xml
+++ b/app/src/main/res/layout/activity_auth.xml
@@ -48,7 +48,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="12dp"
- android:visibility="invisible">
+ android:visibility="gone">
+
+
+
+
+
+