· 6 years ago · Oct 22, 2019, 06:38 AM
1/*-
2 * #%L
3 * Demo Fingerprint Authentication Activity
4 * %%
5 * Copyright (C) 2019 Headspin Inc.
6 * %%
7 * #L%
8 */
9package com.nextunicorn.app;
10
11import android.annotation.TargetApi;
12import android.support.v7.app.AppCompatActivity;
13import android.os.Bundle;
14import android.os.CancellationSignal;
15import android.content.Context;
16import android.app.KeyguardManager;
17import android.hardware.fingerprint.FingerprintManager;
18import android.hardware.fingerprint.FingerprintManager.*;
19import android.support.v4.app.ActivityCompat;
20import android.widget.Toast;
21import android.Manifest;
22import android.content.Intent;
23import android.content.pm.PackageManager;
24import android.security.keystore.KeyProperties;
25import java.security.KeyStore;
26import java.security.NoSuchAlgorithmException;
27import java.security.NoSuchProviderException;
28import javax.crypto.KeyGenerator;
29import android.security.keystore.KeyGenParameterSpec;
30import java.security.cert.CertificateException;
31import java.security.InvalidAlgorithmParameterException;
32import java.io.IOException;
33import android.security.keystore.KeyPermanentlyInvalidatedException;
34import android.support.annotation.RequiresApi;
35import android.util.Log;
36import java.security.InvalidKeyException;
37import java.security.KeyStoreException;
38import java.security.UnrecoverableKeyException;
39import javax.crypto.NoSuchPaddingException;
40import javax.crypto.SecretKey;
41import javax.crypto.Cipher;
42
43// Import from HeadSpin biometrics library
44import io.headspin.instruments.fingerprint.HSFingerprintManager;
45import io.headspin.instruments.fingerprint.HSFingerprintAuthCallback;
46
47@TargetApi(28)
48@RequiresApi(23)
49class DemoFingerprintActivity extends AppCompatActivity {
50
51 private static String TAG = "DemoFingerprintActivity";
52
53 private static String KEY_NAME = "hot_key";
54
55 private HSFingerprintManager hsFingerprintManager;
56
57 private KeyguardManager keyguardManager;
58
59 private KeyStore keyStore;
60
61 private KeyGenerator keyGenerator;
62
63 private Cipher cipher;
64
65 private CryptoObject cryptoObject;
66
67 private CancellationSignal cancellationSignal;
68
69 /**
70 * Inherit [HSFingerprintAuthCallback] to get default toast messages or
71 * or [android.hardware.fingerprint.FingerprintManager.AuthenticationCallback]
72 * to implement your own callbacks.
73 */
74 private HSFingerprintCallback authCallback = new HSFingerprintAuthCallback() {
75 @Override
76 void onAuthenticationSucceeded(AuthenticationResult result) {
77 super.onAuthenticationSucceeded(result);
78 new Handler().postDelayed(new Runnable() {
79 @Override
80 public void run() {
81 finish();
82 }
83 }, 2000);
84 }
85 };
86
87 @Override
88 void onCreate(Bundle savedInstanceState) {
89
90 Log.i(TAG, "creating DemoFingerprintActivity")
91
92 super.onCreate(savedInstanceState);
93
94 hsfingerprintManager = new HSFingerprintManager(this);
95
96 setContentView(R.layout.activity_fingerprint);
97
98 if (managersReady()) {
99 generateKey();
100 if (initCipher()) {
101 cryptoObject = new CryptoObject(cipher);
102 cancellationSignal = new CancellationSignal();
103
104 if (hsFingerprintManager.ready()) {
105 /*
106 * authenticate() sends authCallback to the underlying HSfingerprintService
107 * so it can be called by Headspin biometrics API.
108 */
109 hsFingerprintManager.authenticate(cryptoObject, cancellationSignal,
110 0, authCallback, null);
111 }
112 }
113 }
114 }
115
116 @Override
117 void onStop() {
118 super.onStop();
119 // IMPORTANT: call close() to stop the HSFingerprintService.
120 hsFingerprintManager.close();
121 }
122
123 /*
124 * This is a sample and thus using CBC Block mode should be good enough.
125 * However, please take care to implement a more secure key for your app.
126 */
127 private boolean initCipher() {
128 try {
129 cipher = Cipher.getInstance(
130 KeyProperties.KEY_ALGORITHM_AES + "/"
131 + KeyProperties.BLOCK_MODE_CBC + "/"
132 + KeyProperties.ENCRYPTION_PADDING_PKCS7);
133 } catch (NoSuchAlgorithmException e) {
134 throw RuntimeException("Failed to get Cipher", e);
135 } catch (NoSuchPaddingException e) {
136 throw RuntimeException("Failed to get Cipher", e);
137 }
138
139 try {
140 if (keyStore != null) {
141 keyStore.load(null);
142 SecretKey key = (SecretKey) keyStore.getKey(KEY_NAME, null);
143 cipher.init(Cipher.ENCRYPT_MODE, key);
144 return true;
145 }
146 } catch (KeyPermanentlyInvalidatedException e) {
147 return false;
148 } catch (KeyStoreException e) {
149 throw RuntimeException("Failed to init Cipher", e);
150 } catch (CertificateException e) {
151 throw RuntimeException("Failed to init Cipher", e);
152 } catch (UnrecoverableKeyException e) {
153 throw RuntimeException("Failed to init Cipher", e);
154 } catch (IOException e) {
155 throw RuntimeException("Failed to init Cipher", e);
156 } catch (NoSuchAlgorithmException e) {
157 throw RuntimeException("Failed to init Cipher", e)
158 } catch (InvalidKeyException e) {
159 throw RuntimeException("Failed to init Cipher", e)
160 }
161 }
162
163 private void generateKey() {
164 try {
165 keyStore = KeyStore.getInstance("AndroidKeyStore");
166 } catch (Exception e) {
167 e.printStackTrace();
168 }
169
170 try {
171 keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES,
172 "AndroidKeyStore");
173 } catch (NoSuchAlgorithmException e) {
174 throw RuntimeException("Failed to get KeyGenerator instance", e);
175
176 } catch (NoSuchProviderException e) {
177 throw RuntimeException("Failed to get KeyGenerator instance", e);
178 }
179
180 try {
181 if (keyStore != null) {
182 keyStore.load(null);
183 keyGenerator.init(KeyGenParameterSpec.Builder(
184 KEY_NAME,
185 KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT
186 ).setBlockModes(KeyProperties.BLOCK_MODE_CBC)
187 .setUserAuthenticationRequired(true)
188 .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7)
189 .build());
190
191 keyGenerator.generateKey();
192 }
193 } catch (NoSuchAlgorithmException e ) {
194 throw RuntimeException(e);
195 } catch (InvalidAlgorithmParameterException e) {
196 throw RuntimeException(e);
197 } catch (CertificateException e) {
198 throw RuntimeException(e);
199 } catch (IOException e) {
200 throw RuntimeException(e);
201 }
202 }
203
204 private Boolean managersReady() {
205 KeyguardManager keyguardManager = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);
206
207 /*
208 * HSFingerprintManager fashions a ready() method that takes care of
209 * inquiring the wrapped FingerprintManager's readiness.
210 */
211 if ((keyguardManager == null) || (!hsfingerprintManager.ready())) {
212 return false;
213 }
214
215 if (keyguardManager.isKeyguardSecure == false) {
216 Toast.makeText(this,
217 "Lock screen security is not enabled in Settings",
218 Toast.LENGTH_LONG).show();
219 return false;
220 }
221
222 if (ActivityCompat.checkSelfPermission(this,
223 Manifest.permission.USE_FINGERPRINT) !=
224 PackageManager.PERMISSION_GRANTED) {
225 Toast.makeText(this,
226 "Fingerprint authentication permission not enabled",
227 Toast.LENGTH_LONG).show();
228 return false;
229 }
230
231 if (hsfingerprintManager?.hasEnrolledFingerprints() == false) {
232 Toast.makeText(this,
233 "Register at least one fingerprint in Settings",
234 Toast.LENGTH_LONG).show();
235 return false;
236 }
237 return true;
238 }
239}