· 7 years ago · Oct 19, 2018, 04:08 PM
1public class LoginActivity extends AppCompatActivity {
2
3 //Fingerprint authorization
4 private final String KEY_NAME = "FingerPrintKey";
5 FingerprintManagerCompat fingerprintManager;
6
7 KeyStore keyStore;
8 KeyGenerator keyGenerator;
9 Cipher cipher;
10 FingerprintManagerCompat.CryptoObject cryptoObject;
11 SecretKey key;
12
13 @RequiresApi(api = 23)
14 private BiometricDialog mBioDialog;
15
16
17 @Override
18 protected void onCreate(Bundle savedInstanceState) {
19 super.onCreate(savedInstanceState);
20 setContentView(R.layout.activity_login);
21
22 // Checking shared preferences to see if fingerprint sign in is enabled
23
24 if (bioEnabled) {
25 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
26 showBioMetricDialog();
27 }
28 }
29 }
30
31
32 // Method to show the dialog prompting for fingerprint
33 @RequiresApi(api = 23)
34 private void showBioMetricDialog() {
35
36 //Android P uses Biometric Prompt
37 if (Build.VERSION.SDK_INT >= 28) {
38 BiometricCallback biometricCallback = new BiometricCallback();
39 displayBiometricPrompt(biometricCallback);
40
41 //Older versions use Android's Keystore
42 } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
43 fingerprintManager = FingerprintManagerCompat.from(this);
44
45 if (fingerprintManager.isHardwareDetected()
46 && fingerprintManager.hasEnrolledFingerprints()) {
47 generateKey();
48
49 if (initCipher()) {
50 cryptoObject = new FingerprintManagerCompat.CryptoObject(cipher);
51 FingerPrintCallback callback = new FingerPrintCallback();
52 fingerprintManager.authenticate(cryptoObject, 0,
53 new android.support.v4.os.CancellationSignal(),
54 callback, null);
55
56 mBioDialog = new BiometricDialog(this, callback);
57 mBioDialog.setTitle(getString(R.string.bio_dialog_title));
58 mBioDialog.setSubtitle(getString(R.string.bio_dialog_subtitle));
59 mBioDialog.setDescription(getString(R.string.bio_dialog_finger_desc));
60 mBioDialog.setNegativeButtonText(getString(R.string.bio_dialog_negative));
61 mBioDialog.show();
62 }
63 }
64 }
65 }
66
67
68 @RequiresApi(api = Build.VERSION_CODES.M)
69 private void generateKey() {
70 try {
71
72 keyStore = KeyStore.getInstance("AndroidKeyStore");
73 keyStore.load(null);
74
75 keyGenerator = KeyGenerator.getInstance(
76 KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore");
77 keyGenerator.init(new KeyGenParameterSpec.Builder(KEY_NAME, KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
78 .setBlockModes(KeyProperties.BLOCK_MODE_CBC)
79 .setUserAuthenticationRequired(true)
80 .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7)
81 .build());
82 keyGenerator.generateKey();
83
84 } catch (KeyStoreException
85 | NoSuchAlgorithmException
86 | NoSuchProviderException
87 | InvalidAlgorithmParameterException
88 | CertificateException
89 | IOException e) {
90 e.printStackTrace();
91 }
92 }
93
94
95 @RequiresApi(api = Build.VERSION_CODES.M)
96 private boolean initCipher() {
97 try {
98 cipher = Cipher.getInstance(KeyProperties.KEY_ALGORITHM_AES + "/"
99 + KeyProperties.BLOCK_MODE_CBC + "/" + KeyProperties.ENCRYPTION_PADDING_PKCS7);
100 } catch (NoSuchAlgorithmException
101 | NoSuchPaddingException e) {
102 throw new RuntimeException("Failed to get Cipher", e);
103 }
104
105 try {
106 keyStore.load(null);
107 key = (SecretKey) keyStore.getKey(KEY_NAME, null);
108 cipher.init(Cipher.ENCRYPT_MODE, key);
109 return true;
110 } catch (KeyPermanentlyInvalidatedException e) {
111 return false;
112 } catch (KeyStoreException | CertificateException
113 | UnrecoverableKeyException | IOException
114 | NoSuchAlgorithmException | InvalidKeyException e) {
115 throw new RuntimeException("Failed to init Cipher", e);
116 }
117 }
118
119
120 @Override
121 protected void onDestroy() {
122 super.onDestroy();
123 if (Build.VERSION.SDK_INT >= 23) {
124 if (mBioDialog != null && mBioDialog.isShowing())
125 mBioDialog.cancel();
126 }
127 }
128
129
130 @RequiresApi(api = 28)
131 private void displayBiometricPrompt(final BiometricCallback callback) {
132
133 CancellationSignal cancellationSignal = new CancellationSignal();
134 cancellationSignal.setOnCancelListener(new CancellationSignal.OnCancelListener() {
135 @Override
136 public void onCancel() {
137 Toast.makeText(LoginActivity.this, "Cancelled", Toast.LENGTH_SHORT).show();
138 }
139 });
140
141 new BiometricPrompt.Builder(this)
142 .setTitle(getString(R.string.bio_dialog_title))
143 .setSubtitle(getString(R.string.bio_dialog_subtitle))
144 .setDescription(getString(R.string.bio_dialog_desc))
145 .setNegativeButton(getString(R.string.bio_dialog_negative), this.getMainExecutor(), new DialogInterface.OnClickListener() {
146
147 @Override
148 public void onClick(DialogInterface dialog, int which) {
149 callback.onAuthenticationCancelled();
150 }
151 }).build().authenticate(cancellationSignal, this.getMainExecutor(), callback);
152 }
153
154
155 private void bioEnabledLogin() {
156 // Fetch login credentials from shared prefs and do a loginTask
157 }
158
159
160 // Inner class for Biometric Authentication callbacks
161 @RequiresApi(api = Build.VERSION_CODES.P)
162 public class BiometricCallback extends android.hardware.biometrics.BiometricPrompt.AuthenticationCallback {
163
164 @Override
165 public void onAuthenticationSucceeded(android.hardware.biometrics.BiometricPrompt.AuthenticationResult result) {
166 super.onAuthenticationSucceeded(result);
167 bioEnabledLogin();
168 }
169
170 // The rest of the callback methods here (they don't currently do anything)
171
172 }
173
174
175 // Inner class for FingerPrintManager Authentication callbacks
176 @RequiresApi(api = Build.VERSION_CODES.M)
177 public class FingerPrintCallback extends FingerprintManagerCompat.AuthenticationCallback {
178 FingerPrintCallback() {
179 super();
180 }
181
182 @Override
183 public void onAuthenticationSucceeded(FingerprintManagerCompat.AuthenticationResult result) {
184 super.onAuthenticationSucceeded(result);
185 mBioDialog.dismiss();
186 bioEnabledLogin();
187 }
188 }
189}
190
19109:48:01.480 15048 15048 W dalvikvm: Unable to resolve superclass of Lcom/example/myapp/LoginActivity$BiometricCallback; (300)
19210-19 09:48:01.480 15048 15048 W dalvikvm: Link of class 'Lcom/example/myapp/LoginActivity$BiometricCallback;' failed
19310-19 09:48:01.480 825 1043 V SmartFaceService - 3rd party pause: onReceive [android.intent.action.ACTIVITY_STATE/com.example.myapp/create]
19410-19 09:48:01.490 15048 15048 E dalvikvm: Could not find class 'android.hardware.biometrics.BiometricPrompt$Builder', referenced from method com.example.myapp.LoginActivity.displayBiometricPrompt
19510-19 09:48:01.490 15048 15048 W dalvikvm: VFY: unable to resolve new-instance 302 (Landroid/hardware/biometrics/BiometricPrompt$Builder;) in Lcom/example/myapp/LoginActivity;
19610-19 09:48:01.490 15048 15048 D dalvikvm: VFY: replacing opcode 0x22 at 0x000d
19710-19 09:48:01.490 15048 15048 E dalvikvm: Could not find class 'android.security.keystore.KeyGenParameterSpec$Builder', referenced from method com.example.myapp.LoginActivity.generateKey
19810-19 09:48:01.490 15048 15048 W dalvikvm: VFY: unable to resolve new-instance 430 (Landroid/security/keystore/KeyGenParameterSpec$Builder;) in Lcom/example/myapp/LoginActivity;
19910-19 09:48:01.490 15048 15048 D dalvikvm: VFY: replacing opcode 0x22 at 0x001a
20010-19 09:48:01.490 15048 15048 W dalvikvm: VFY: unable to resolve exception class 432 (Landroid/security/keystore/KeyPermanentlyInvalidatedException;)
20110-19 09:48:01.490 15048 15048 W dalvikvm: VFY: unable to find exception handler at addr 0x2d
20210-19 09:48:01.490 15048 15048 W dalvikvm: VFY: rejected Lcom/example/myapp/LoginActivity;.initCipher ()Z
20310-19 09:48:01.490 15048 15048 W dalvikvm: VFY: rejecting opcode 0x0d at 0x002d
20410-19 09:48:01.490 15048 15048 W dalvikvm: VFY: rejected Lcom/example/myapp/LoginActivity;.initCipher ()Z
20510-19 09:48:01.490 15048 15048 W dalvikvm: Verifier rejected class Lcom/example/myapp/LoginActivity;
20610-19 09:48:01.490 15048 15048 W dalvikvm: Class init failed in newInstance call (Lcom/example/myapp/LoginActivity;)
20710-19 09:48:01.490 15048 15048 D AndroidRuntime: Shutting down VM
20810-19 09:48:01.490 15048 15048 W dalvikvm: threadid=1: thread exiting with uncaught exception (group=0x417d3da0)
20910-19 09:48:01.490 15048 15048 E AndroidRuntime: FATAL EXCEPTION: main
21010-19 09:48:01.490 15048 15048 E AndroidRuntime: Process: com.example.myapp, PID: 15048
21110-19 09:48:01.490 15048 15048 E AndroidRuntime: java.lang.VerifyError: com/example/myapp/LoginActivity
21210-19 09:48:01.490 15048 15048 E AndroidRuntime: at java.lang.Class.newInstanceImpl(Native Method)
21310-19 09:48:01.490 15048 15048 E AndroidRuntime: at java.lang.Class.newInstance(Class.java:1208)
21410-19 09:48:01.490 15048 15048 E AndroidRuntime: at android.app.Instrumentation.newActivity(Instrumentation.java:1079)
21510-19 09:48:01.490 15048 15048 E AndroidRuntime: at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2199)
21610-19 09:48:01.490 15048 15048 E AndroidRuntime: at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2340)
21710-19 09:48:01.490 15048 15048 E AndroidRuntime: at android.app.ActivityThread.access$800(ActivityThread.java:157)
21810-19 09:48:01.490 15048 15048 E AndroidRuntime: at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1247)
21910-19 09:48:01.490 15048 15048 E AndroidRuntime: at android.os.Handler.dispatchMessage(Handler.java:102)
22010-19 09:48:01.490 15048 15048 E AndroidRuntime: at android.os.Looper.loop(Looper.java:157)
22110-19 09:48:01.490 15048 15048 E AndroidRuntime: at android.app.ActivityThread.main(ActivityThread.java:5293)
22210-19 09:48:01.490 15048 15048 E AndroidRuntime: at java.lang.reflect.Method.invokeNative(Native Method)
22310-19 09:48:01.490 15048 15048 E AndroidRuntime: at java.lang.reflect.Method.invoke(Method.java:515)
22410-19 09:48:01.490 15048 15048 E AndroidRuntime: at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1265)
22510-19 09:48:01.490 15048 15048 E AndroidRuntime: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1081)
22610-19 09:48:01.490 15048 15048 E AndroidRuntime: at dalvik.system.NativeStart.main(Native Method)