mirror of
https://github.com/beemdevelopment/Aegis.git
synced 2025-05-14 22:12:55 +00:00
Add fingerprint support
This commit is contained in:
parent
1deb8910b0
commit
bfe7a1bde0
9 changed files with 321 additions and 95 deletions
|
@ -1,38 +1,84 @@
|
|||
package me.impy.aegis;
|
||||
|
||||
import android.Manifest;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.hardware.fingerprint.FingerprintManager;
|
||||
import android.os.Build;
|
||||
import android.support.v4.app.ActivityCompat;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.os.Bundle;
|
||||
import android.text.Editable;
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
import android.widget.EditText;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.RadioButton;
|
||||
import android.widget.TextView;
|
||||
|
||||
import java.lang.reflect.UndeclaredThrowableException;
|
||||
|
||||
import javax.crypto.BadPaddingException;
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.IllegalBlockSizeException;
|
||||
import javax.crypto.SecretKey;
|
||||
|
||||
import me.impy.aegis.crypto.CryptoUtils;
|
||||
import me.impy.aegis.crypto.KeyStoreHandle;
|
||||
import me.impy.aegis.crypto.MasterKey;
|
||||
import me.impy.aegis.crypto.slots.FingerprintSlot;
|
||||
import me.impy.aegis.crypto.slots.PasswordSlot;
|
||||
import me.impy.aegis.crypto.slots.Slot;
|
||||
import me.impy.aegis.crypto.slots.SlotCollection;
|
||||
import me.impy.aegis.finger.FingerprintUiHelper;
|
||||
import me.impy.aegis.helpers.AuthHelper;
|
||||
|
||||
public class AuthActivity extends AppCompatActivity {
|
||||
public class AuthActivity extends AppCompatActivity implements FingerprintUiHelper.Callback {
|
||||
public static final int RESULT_OK = 0;
|
||||
public static final int RESULT_EXCEPTION = 1;
|
||||
|
||||
private EditText textPassword;
|
||||
|
||||
private SlotCollection slots;
|
||||
private LinearLayout boxFingerprint;
|
||||
private ImageView imgFingerprint;
|
||||
private TextView textFingerprint;
|
||||
private FingerprintUiHelper fingerHelper;
|
||||
private Cipher fingerCipher;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_auth);
|
||||
textPassword = (EditText) findViewById(R.id.text_password);
|
||||
boxFingerprint = (LinearLayout) findViewById(R.id.box_fingerprint);
|
||||
imgFingerprint = (ImageView) findViewById(R.id.img_fingerprint);
|
||||
textFingerprint = (TextView) findViewById(R.id.text_fingerprint);
|
||||
|
||||
Intent intent = getIntent();
|
||||
final SlotCollection slots = (SlotCollection) intent.getSerializableExtra("slots");
|
||||
slots = (SlotCollection) intent.getSerializableExtra("slots");
|
||||
|
||||
// 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
|
||||
Context context = getApplicationContext();
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
FingerprintManager manager = (FingerprintManager) context.getSystemService(Context.FINGERPRINT_SERVICE);
|
||||
if (ActivityCompat.checkSelfPermission(context, Manifest.permission.USE_FINGERPRINT) == PackageManager.PERMISSION_GRANTED && manager.isHardwareDetected()) {
|
||||
if (slots.has(FingerprintSlot.class)) {
|
||||
try {
|
||||
KeyStoreHandle handle = new KeyStoreHandle();
|
||||
if (handle.keyExists()) {
|
||||
SecretKey key = handle.getKey();
|
||||
fingerCipher = Slot.createCipher(key, Cipher.DECRYPT_MODE);
|
||||
fingerHelper = new FingerprintUiHelper(manager, imgFingerprint, textFingerprint, this);
|
||||
boxFingerprint.setVisibility(View.VISIBLE);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new UndeclaredThrowableException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Button button = (Button) findViewById(R.id.button_decrypt);
|
||||
button.setOnClickListener(new View.OnClickListener() {
|
||||
|
@ -42,11 +88,13 @@ public class AuthActivity extends AppCompatActivity {
|
|||
try {
|
||||
if (slots.has(PasswordSlot.class)) {
|
||||
PasswordSlot slot = slots.find(PasswordSlot.class);
|
||||
char[] password = getPassword(true);
|
||||
char[] password = AuthHelper.getPassword(textPassword, true);
|
||||
SecretKey key = slot.deriveKey(password);
|
||||
CryptoUtils.zero(password);
|
||||
Cipher cipher = Slot.createCipher(key, Cipher.DECRYPT_MODE);
|
||||
masterKey = MasterKey.decryptSlot(slot, cipher);
|
||||
} else {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// TODO: feedback
|
||||
|
@ -54,31 +102,57 @@ public class AuthActivity extends AppCompatActivity {
|
|||
}
|
||||
|
||||
// send the master key back to the main activity
|
||||
Intent result = new Intent();
|
||||
result.putExtra("key", masterKey);
|
||||
setResult(RESULT_OK, result);
|
||||
finish();
|
||||
setKey(masterKey);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void setKey(MasterKey key) {
|
||||
// send the master key back to the main activity
|
||||
Intent result = new Intent();
|
||||
result.putExtra("key", key);
|
||||
setResult(RESULT_OK, result);
|
||||
finish();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
// ignore back button presses
|
||||
}
|
||||
|
||||
private char[] getPassword(boolean clear) {
|
||||
char[] password = getEditTextChars(textPassword);
|
||||
if (clear) {
|
||||
textPassword.getText().clear();
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
|
||||
if (fingerHelper != null) {
|
||||
fingerHelper.startListening(new FingerprintManager.CryptoObject(fingerCipher));
|
||||
}
|
||||
return password;
|
||||
}
|
||||
|
||||
private static char[] getEditTextChars(EditText text) {
|
||||
Editable editable = text.getText();
|
||||
char[] chars = new char[editable.length()];
|
||||
editable.getChars(0, editable.length(), chars, 0);
|
||||
return chars;
|
||||
@Override
|
||||
public void onPause() {
|
||||
super.onPause();
|
||||
|
||||
if (fingerHelper != null) {
|
||||
fingerHelper.stopListening();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAuthenticated() {
|
||||
MasterKey key;
|
||||
FingerprintSlot slot = slots.find(FingerprintSlot.class);
|
||||
try {
|
||||
key = new MasterKey(slot.getKey(fingerCipher));
|
||||
} catch (Exception e) {
|
||||
throw new UndeclaredThrowableException(e);
|
||||
}
|
||||
|
||||
setKey(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError() {
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,42 +1,57 @@
|
|||
package me.impy.aegis;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.hardware.fingerprint.FingerprintManager;
|
||||
import android.os.Bundle;
|
||||
import android.support.design.widget.Snackbar;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.text.Editable;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.EditText;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.github.paolorotolo.appintro.ISlidePolicy;
|
||||
import com.github.paolorotolo.appintro.ISlideSelectionListener;
|
||||
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.spec.InvalidKeySpecException;
|
||||
import java.util.Arrays;
|
||||
import java.lang.reflect.UndeclaredThrowableException;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.NoSuchPaddingException;
|
||||
import javax.crypto.SecretKey;
|
||||
|
||||
import me.impy.aegis.crypto.CryptoUtils;
|
||||
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.Slot;
|
||||
import me.impy.aegis.finger.FingerprintUiHelper;
|
||||
import me.impy.aegis.helpers.AuthHelper;
|
||||
|
||||
public class CustomAuthenticatedSlide extends Fragment implements ISlidePolicy, ISlideSelectionListener {
|
||||
public class CustomAuthenticatedSlide extends Fragment implements FingerprintUiHelper.Callback, ISlidePolicy, ISlideSelectionListener {
|
||||
private int cryptType;
|
||||
private EditText textPassword;
|
||||
private EditText textPasswordConfirm;
|
||||
private int bgColor;
|
||||
|
||||
private LinearLayout boxFingerprint;
|
||||
private ImageView imgFingerprint;
|
||||
private TextView textFingerprint;
|
||||
private FingerprintUiHelper fingerHelper;
|
||||
private KeyStoreHandle storeHandle;
|
||||
private Cipher fingerCipher;
|
||||
private boolean fingerAuthenticated;
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
final View view = inflater.inflate(R.layout.fragment_authenticated_slide, container, false);
|
||||
textPassword = (EditText) view.findViewById(R.id.text_password);
|
||||
textPasswordConfirm = (EditText) view.findViewById(R.id.text_password_confirm);
|
||||
boxFingerprint = (LinearLayout) view.findViewById(R.id.box_fingerprint);
|
||||
imgFingerprint = (ImageView) view.findViewById(R.id.img_fingerprint);
|
||||
textFingerprint = (TextView) view.findViewById(R.id.text_fingerprint);
|
||||
view.findViewById(R.id.main).setBackgroundColor(bgColor);
|
||||
return view;
|
||||
}
|
||||
|
@ -50,46 +65,17 @@ public class CustomAuthenticatedSlide extends Fragment implements ISlidePolicy,
|
|||
return cryptType;
|
||||
}
|
||||
|
||||
public Cipher getCipher(PasswordSlot slot, int mode)
|
||||
throws InvalidKeySpecException, NoSuchAlgorithmException,
|
||||
InvalidKeyException, NoSuchPaddingException {
|
||||
char[] password = getPassword(true);
|
||||
byte[] salt = CryptoUtils.generateSalt();
|
||||
SecretKey key = slot.deriveKey(password, salt, CryptoUtils.CRYPTO_SCRYPT_N, CryptoUtils.CRYPTO_SCRYPT_r, CryptoUtils.CRYPTO_SCRYPT_p);
|
||||
CryptoUtils.zero(password);
|
||||
|
||||
return Slot.createCipher(key, mode);
|
||||
}
|
||||
|
||||
private char[] getPassword(boolean clear) {
|
||||
char[] password = getEditTextChars(textPassword);
|
||||
if (clear) {
|
||||
textPassword.getText().clear();
|
||||
}
|
||||
return password;
|
||||
}
|
||||
|
||||
private static char[] getEditTextChars(EditText text) {
|
||||
Editable editable = text.getText();
|
||||
char[] chars = new char[editable.length()];
|
||||
editable.getChars(0, editable.length(), chars, 0);
|
||||
return chars;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSlideSelected() {
|
||||
Intent intent = getActivity().getIntent();
|
||||
cryptType = intent.getIntExtra("cryptType", 1337);
|
||||
|
||||
switch(cryptType) {
|
||||
case CustomAuthenticationSlide.CRYPT_TYPE_NONE:
|
||||
break;
|
||||
case CustomAuthenticationSlide.CRYPT_TYPE_PASS:
|
||||
break;
|
||||
case CustomAuthenticationSlide.CRYPT_TYPE_FINGER:
|
||||
break;
|
||||
default:
|
||||
throw new RuntimeException();
|
||||
public Cipher getCipher(Slot slot) throws Exception {
|
||||
if (slot instanceof PasswordSlot) {
|
||||
char[] password = AuthHelper.getPassword(textPassword, true);
|
||||
byte[] salt = CryptoUtils.generateSalt();
|
||||
SecretKey key = ((PasswordSlot)slot).deriveKey(password, salt, CryptoUtils.CRYPTO_SCRYPT_N, CryptoUtils.CRYPTO_SCRYPT_r, CryptoUtils.CRYPTO_SCRYPT_p);
|
||||
CryptoUtils.zero(password);
|
||||
return Slot.createCipher(key, Cipher.ENCRYPT_MODE);
|
||||
} else if (slot instanceof FingerprintSlot) {
|
||||
return fingerCipher;
|
||||
} else {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -97,8 +83,57 @@ public class CustomAuthenticatedSlide extends Fragment implements ISlidePolicy,
|
|||
bgColor = color;
|
||||
}
|
||||
|
||||
@Override
|
||||
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();
|
||||
}
|
||||
// TODO: consider regenerating the key if it exists
|
||||
if (!storeHandle.keyExists()) {
|
||||
key = storeHandle.generateKey(true);
|
||||
} else {
|
||||
key = storeHandle.getKey();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new UndeclaredThrowableException(e);
|
||||
}
|
||||
|
||||
if (fingerHelper == null) {
|
||||
FingerprintManager fingerManager = (FingerprintManager) getContext().getSystemService(Context.FINGERPRINT_SERVICE);
|
||||
fingerHelper = new FingerprintUiHelper(fingerManager, imgFingerprint, textFingerprint, this);
|
||||
}
|
||||
|
||||
try {
|
||||
fingerCipher = Slot.createCipher(key, Cipher.ENCRYPT_MODE);
|
||||
} catch (Exception e) {
|
||||
throw new UndeclaredThrowableException(e);
|
||||
}
|
||||
fingerHelper.startListening(new FingerprintManager.CryptoObject(fingerCipher));
|
||||
break;
|
||||
default:
|
||||
throw new RuntimeException();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSlideDeselected() {
|
||||
if (fingerHelper != null) {
|
||||
fingerAuthenticated = false;
|
||||
boxFingerprint.setVisibility(View.INVISIBLE);
|
||||
fingerHelper.stopListening();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -106,15 +141,13 @@ public class CustomAuthenticatedSlide extends Fragment implements ISlidePolicy,
|
|||
switch(cryptType) {
|
||||
case CustomAuthenticationSlide.CRYPT_TYPE_NONE:
|
||||
return true;
|
||||
case CustomAuthenticationSlide.CRYPT_TYPE_PASS:
|
||||
char[] password = getEditTextChars(textPassword);
|
||||
char[] passwordConfirm = getEditTextChars(textPasswordConfirm);
|
||||
boolean equal = password.length != 0 && Arrays.equals(password, passwordConfirm);
|
||||
CryptoUtils.zero(password);
|
||||
CryptoUtils.zero(passwordConfirm);
|
||||
return equal;
|
||||
case CustomAuthenticationSlide.CRYPT_TYPE_FINGER:
|
||||
return false;
|
||||
if (!fingerAuthenticated) {
|
||||
return false;
|
||||
}
|
||||
// intentional fallthrough
|
||||
case CustomAuthenticationSlide.CRYPT_TYPE_PASS:
|
||||
return AuthHelper.arePasswordsEqual(textPassword, textPasswordConfirm);
|
||||
default:
|
||||
throw new RuntimeException();
|
||||
}
|
||||
|
@ -122,10 +155,29 @@ public class CustomAuthenticatedSlide extends Fragment implements ISlidePolicy,
|
|||
|
||||
@Override
|
||||
public void onUserIllegallyRequestedNextPage() {
|
||||
String message;
|
||||
if (!AuthHelper.arePasswordsEqual(textPassword, textPasswordConfirm)) {
|
||||
message = "Passwords should be equal and non-empty";
|
||||
} else if (!fingerAuthenticated) {
|
||||
message = "Register your fingerprint";
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
View view = getView();
|
||||
if (view != null) {
|
||||
Snackbar snackbar = Snackbar.make(getView(), "Passwords should be equal and non-empty", Snackbar.LENGTH_LONG);
|
||||
Snackbar snackbar = Snackbar.make(getView(), message, Snackbar.LENGTH_LONG);
|
||||
snackbar.show();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAuthenticated() {
|
||||
fingerAuthenticated = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError() {
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,11 +13,9 @@ import android.support.v4.app.Fragment;
|
|||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.RadioButton;
|
||||
import android.widget.RadioGroup;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.github.paolorotolo.appintro.ISlidePolicy;
|
||||
|
||||
|
@ -53,9 +51,6 @@ public class CustomAuthenticationSlide extends Fragment implements ISlidePolicy
|
|||
break;
|
||||
case R.id.rb_fingerprint:
|
||||
id = CRYPT_TYPE_FINGER;
|
||||
// TODO: remove this
|
||||
group.clearCheck();
|
||||
Toast.makeText(context, "Fingerprint is not supported yet", Toast.LENGTH_SHORT).show();
|
||||
break;
|
||||
default:
|
||||
throw new RuntimeException();
|
||||
|
|
|
@ -15,6 +15,7 @@ import javax.crypto.Cipher;
|
|||
|
||||
import me.impy.aegis.crypto.CryptResult;
|
||||
import me.impy.aegis.crypto.MasterKey;
|
||||
import me.impy.aegis.crypto.slots.FingerprintSlot;
|
||||
import me.impy.aegis.crypto.slots.PasswordSlot;
|
||||
import me.impy.aegis.crypto.slots.SlotCollection;
|
||||
import me.impy.aegis.db.Database;
|
||||
|
@ -107,13 +108,13 @@ public class IntroActivity extends AppIntro {
|
|||
}
|
||||
}
|
||||
|
||||
SlotCollection slots = databaseFile.getSlots();
|
||||
if (cryptType != CustomAuthenticationSlide.CRYPT_TYPE_NONE) {
|
||||
try {
|
||||
// encrypt the master key with a key derived from the user's password
|
||||
// and add it to the list of slots
|
||||
SlotCollection slots = databaseFile.getSlots();
|
||||
PasswordSlot slot = new PasswordSlot();
|
||||
Cipher cipher = authenticatedSlide.getCipher(slot, Cipher.ENCRYPT_MODE);
|
||||
Cipher cipher = authenticatedSlide.getCipher(slot);
|
||||
masterKey.encryptSlot(slot, cipher);
|
||||
slots.add(slot);
|
||||
} catch (Exception e) {
|
||||
|
@ -122,8 +123,18 @@ public class IntroActivity extends AppIntro {
|
|||
}
|
||||
}
|
||||
|
||||
if (cryptType != CustomAuthenticationSlide.CRYPT_TYPE_FINGER) {
|
||||
// TODO
|
||||
if (cryptType == CustomAuthenticationSlide.CRYPT_TYPE_FINGER) {
|
||||
try {
|
||||
// encrypt the master key with the fingerprint key
|
||||
// and add it to the list of slots
|
||||
FingerprintSlot slot = new FingerprintSlot();
|
||||
Cipher cipher = authenticatedSlide.getCipher(slot);
|
||||
masterKey.encryptSlot(slot, cipher);
|
||||
slots.add(slot);
|
||||
} catch (Exception e) {
|
||||
setException(e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// finally, save the database
|
||||
|
|
|
@ -25,7 +25,7 @@ public abstract class Slot implements Serializable {
|
|||
// getKey decrypts the encrypted master key in this slot with the given key and returns it.
|
||||
public SecretKey getKey(Cipher cipher) throws BadPaddingException, IllegalBlockSizeException {
|
||||
byte[] decryptedKeyBytes = cipher.doFinal(_encryptedMasterKey);
|
||||
SecretKey decryptedKey = new SecretKeySpec(decryptedKeyBytes, CryptoUtils.CRYPTO_CIPHER_RAW);
|
||||
SecretKey decryptedKey = new SecretKeySpec(decryptedKeyBytes, CryptoUtils.CRYPTO_CIPHER_AEAD);
|
||||
CryptoUtils.zero(decryptedKeyBytes);
|
||||
return decryptedKey;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
package me.impy.aegis.finger;
|
||||
// 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
|
||||
|
@ -16,6 +17,8 @@ package me.impy.aegis.finger;
|
|||
* limitations under the License
|
||||
*/
|
||||
|
||||
package me.impy.aegis.finger;
|
||||
|
||||
import android.hardware.fingerprint.FingerprintManager;
|
||||
import android.os.Build;
|
||||
import android.os.CancellationSignal;
|
||||
|
@ -109,8 +112,6 @@ public class FingerprintUiHelper extends FingerprintManager.AuthenticationCallba
|
|||
public void onAuthenticationSucceeded(FingerprintManager.AuthenticationResult result) {
|
||||
mErrorTextView.removeCallbacks(mResetErrorTextRunnable);
|
||||
mIcon.setImageResource(R.drawable.ic_fingerprint_success);
|
||||
mErrorTextView.setTextColor(
|
||||
mErrorTextView.getResources().getColor(R.color.success_color, null));
|
||||
mErrorTextView.setText(
|
||||
mErrorTextView.getResources().getString(R.string.fingerprint_success));
|
||||
mIcon.postDelayed(new Runnable() {
|
||||
|
@ -124,8 +125,6 @@ public class FingerprintUiHelper extends FingerprintManager.AuthenticationCallba
|
|||
private void showError(CharSequence error) {
|
||||
mIcon.setImageResource(R.drawable.ic_fingerprint_error);
|
||||
mErrorTextView.setText(error);
|
||||
mErrorTextView.setTextColor(
|
||||
mErrorTextView.getResources().getColor(R.color.warning_color, null));
|
||||
mErrorTextView.removeCallbacks(mResetErrorTextRunnable);
|
||||
mErrorTextView.postDelayed(mResetErrorTextRunnable, ERROR_TIMEOUT_MILLIS);
|
||||
}
|
||||
|
@ -133,8 +132,6 @@ public class FingerprintUiHelper extends FingerprintManager.AuthenticationCallba
|
|||
private Runnable mResetErrorTextRunnable = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mErrorTextView.setTextColor(
|
||||
mErrorTextView.getResources().getColor(R.color.hint_color, null));
|
||||
mErrorTextView.setText(
|
||||
mErrorTextView.getResources().getString(R.string.fingerprint_hint));
|
||||
mIcon.setImageResource(R.drawable.ic_fp_40px);
|
||||
|
|
38
app/src/main/java/me/impy/aegis/helpers/AuthHelper.java
Normal file
38
app/src/main/java/me/impy/aegis/helpers/AuthHelper.java
Normal file
|
@ -0,0 +1,38 @@
|
|||
package me.impy.aegis.helpers;
|
||||
|
||||
import android.text.Editable;
|
||||
import android.widget.EditText;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import me.impy.aegis.crypto.CryptoUtils;
|
||||
|
||||
public class AuthHelper {
|
||||
private AuthHelper() {
|
||||
}
|
||||
|
||||
public static char[] getPassword(EditText text, boolean clear) {
|
||||
char[] password = getEditTextChars(text);
|
||||
if (clear) {
|
||||
text.getText().clear();
|
||||
}
|
||||
return password;
|
||||
}
|
||||
|
||||
public static char[] getEditTextChars(EditText text) {
|
||||
Editable editable = text.getText();
|
||||
char[] chars = new char[editable.length()];
|
||||
editable.getChars(0, editable.length(), chars, 0);
|
||||
return chars;
|
||||
}
|
||||
|
||||
public static boolean arePasswordsEqual(EditText text1, EditText text2) {
|
||||
char[] password = getEditTextChars(text1);
|
||||
char[] passwordConfirm = getEditTextChars(text2);
|
||||
boolean equal = password.length != 0 && Arrays.equals(password, passwordConfirm);
|
||||
CryptoUtils.zero(password);
|
||||
CryptoUtils.zero(passwordConfirm);
|
||||
return equal;
|
||||
}
|
||||
|
||||
}
|
|
@ -8,8 +8,8 @@
|
|||
tools:context="me.impy.aegis.AuthActivity">
|
||||
<LinearLayout
|
||||
android:orientation="vertical"
|
||||
android:layout_width="344dp"
|
||||
android:layout_height="495dp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="32dp"
|
||||
tools:layout_editor_absoluteY="8dp"
|
||||
tools:layout_editor_absoluteX="8dp">
|
||||
|
@ -40,5 +40,26 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:text="Decrypt" />
|
||||
</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="invisible">
|
||||
|
||||
<ImageView
|
||||
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_gravity="center_vertical"
|
||||
android:layout_marginLeft="15dp"
|
||||
android:text="Touch sensor"/>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</android.support.design.widget.CoordinatorLayout>
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
<LinearLayout
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="12dp">
|
||||
|
||||
<TextView
|
||||
|
@ -61,4 +61,42 @@
|
|||
|
||||
</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="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">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/img_fingerprint"
|
||||
android:layout_width="60dp"
|
||||
android:layout_height="60dp" />
|
||||
|
||||
<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="Touch sensor"/>
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue