· 6 years ago · Aug 16, 2019, 01:38 PM
1import android.Manifest;
2import android.app.Dialog;
3import android.app.KeyguardManager;
4import android.content.Context;
5import android.content.Intent;
6import android.content.pm.ActivityInfo;
7import android.content.pm.PackageManager;
8import android.hardware.fingerprint.FingerprintManager;
9import android.os.Bundle;
10import android.os.CancellationSignal;
11import android.security.keystore.KeyGenParameterSpec;
12import android.security.keystore.KeyProperties;
13import android.support.annotation.NonNull;
14import android.support.v4.app.ActivityCompat;
15import android.support.v7.app.AppCompatActivity;
16import android.text.TextUtils;
17import android.util.Log;
18import android.view.View;
19import android.view.Window;
20import android.view.WindowManager;
21import android.widget.Button;
22import android.widget.EditText;
23import android.widget.ImageView;
24import android.widget.Toast;
25import com.google.gson.Gson;
26import java.io.IOException;
27import java.security.InvalidAlgorithmParameterException;
28import java.security.InvalidKeyException;
29import java.security.KeyStore;
30import java.security.KeyStoreException;
31import java.security.NoSuchAlgorithmException;
32import java.security.NoSuchProviderException;
33import java.security.UnrecoverableKeyException;
34import java.security.cert.CertificateException;
35import javax.crypto.Cipher;
36import javax.crypto.KeyGenerator;
37import javax.crypto.NoSuchPaddingException;
38import javax.crypto.SecretKey;
39public class LoginActivity extends AppCompatActivity {
40 private static final String TAG = LoginActivity.class.getSimpleName();
41 private FingerprintManager fingerprintManager;
42 private KeyguardManager keyguardManager;
43 private KeyStore keyStore;
44 private KeyGenerator keyGenerator;
45 private Cipher cipher;
46 private FingerprintManager.CryptoObject cryptoObject;
47 private FingerprintHandler fingerprintHandler;
48 private static final String FINGERPRINT_KEY = "key_name";
49 private static final int REQUEST_USE_FINGERPRINT = 300;
50 protected static Gson mGson;
51 protected static CustomSharedPreference mPref;
52 private static UserObject mUser;
53 private static String userString;
54 @Override
55 protected void onCreate(Bundle savedInstanceState) {
56 requestWindowFeature(Window.FEATURE_NO_TITLE);
57 getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
58 super.onCreate(savedInstanceState);
59 setContentView(R.layout.activity_login);
60 setTitle("Android Fingerprint Login");
61 setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
62 mGson = ((CustomApplication)getApplication()).getGsonObject();
63 mPref = ((CustomApplication)getApplication()).getShared();
64 fingerprintHandler = new FingerprintHandler(this);
65 fingerprintManager = (FingerprintManager) getSystemService(FINGERPRINT_SERVICE);
66 keyguardManager = (KeyguardManager) getSystemService(KEYGUARD_SERVICE);
67 // check support for android fingerprint on device
68 checkDeviceFingerprintSupport();
69 //generate fingerprint keystore
70 generateFingerprintKeyStore();
71 //instantiate Cipher class
72 Cipher mCipher = instantiateCipher();
73 if(mCipher != null){
74 cryptoObject = new FingerprintManager.CryptoObject(mCipher);
75 }
76 ImageView fingerprintImage = (ImageView)findViewById(R.id.fingerprint_image);
77 fingerprintImage.setOnClickListener(new View.OnClickListener() {
78 @Override
79 public void onClick(View view) {
80 fingerprintHandler.completeFingerAuthentication(fingerprintManager, cryptoObject);
81 }
82 });
83 }
84 private void checkDeviceFingerprintSupport() {
85 if (ActivityCompat.checkSelfPermission(this, Manifest.permission.USE_FINGERPRINT) != PackageManager.PERMISSION_GRANTED) {
86 ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.USE_FINGERPRINT}, REQUEST_USE_FINGERPRINT);
87 } else {
88 if (!fingerprintManager.isHardwareDetected()) {
89 Toast.makeText(LoginActivity.this, "Fingerprint is not supported in this device", Toast.LENGTH_LONG).show();
90 }
91 if (!fingerprintManager.hasEnrolledFingerprints()) {
92 Toast.makeText(LoginActivity.this, "Fingerprint not yet configured", Toast.LENGTH_LONG).show();
93 }
94 if (!keyguardManager.isKeyguardSecure()) {
95 Toast.makeText(LoginActivity.this, "Screen lock is not secure and enable", Toast.LENGTH_LONG).show();
96 }
97 return;
98 }
99 }
100 private void generateFingerprintKeyStore(){
101 try {
102 keyStore = KeyStore.getInstance("AndroidKeyStore");
103 } catch (KeyStoreException e) {
104 e.printStackTrace();
105 }
106 try {
107 keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore");
108 } catch (NoSuchAlgorithmException e) {
109 e.printStackTrace();
110 } catch (NoSuchProviderException e) {
111 e.printStackTrace();
112 }
113 try {
114 keyGenerator.init(new KeyGenParameterSpec.Builder(FINGERPRINT_KEY, KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
115 .setBlockModes(KeyProperties.BLOCK_MODE_CBC)
116 .setUserAuthenticationRequired(true)
117 .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7)
118 .build());
119 } catch (InvalidAlgorithmParameterException e) {
120 e.printStackTrace();
121 }
122 keyGenerator.generateKey();
123 }
124 private Cipher instantiateCipher(){
125 try {
126 cipher = Cipher.getInstance(KeyProperties.KEY_ALGORITHM_AES + "/" + KeyProperties.BLOCK_MODE_CBC + "/" + KeyProperties.ENCRYPTION_PADDING_PKCS7);
127 keyStore.load(null);
128 SecretKey secretKey = (SecretKey)keyStore.getKey(FINGERPRINT_KEY, null);
129 cipher.init(Cipher.ENCRYPT_MODE, secretKey);
130 return cipher;
131 } catch (NoSuchAlgorithmException | NoSuchPaddingException | UnrecoverableKeyException |
132 CertificateException | IOException | KeyStoreException | InvalidKeyException e) {
133 throw new RuntimeException("Failed to instantiate Cipher class");
134 }
135 }
136 @Override
137 public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
138 if(requestCode == REQUEST_USE_FINGERPRINT){
139 if(grantResults[0] == PackageManager.PERMISSION_GRANTED){
140 // check support for android fingerprint on device
141 checkDeviceFingerprintSupport();
142 //generate fingerprint keystore
143 generateFingerprintKeyStore();
144 //instantiate Cipher class
145 Cipher mCipher = instantiateCipher();
146 if(mCipher != null){
147 cryptoObject = new FingerprintManager.CryptoObject(mCipher);
148 }
149 }
150 else{
151 Toast.makeText(this, R.string.permission_refused, Toast.LENGTH_LONG).show();
152 }
153 }else{
154 Toast.makeText(this, getString(R.string.Unknown_permission_request), Toast.LENGTH_LONG).show();
155 }
156 }
157 public static class FingerprintHandler extends FingerprintManager.AuthenticationCallback{
158 private static final String TAG = FingerprintHandler.class.getSimpleName();
159 private Context context;
160 public FingerprintHandler(Context context){
161 this.context = context;
162 }
163 @Override
164 public void onAuthenticationError(int errorCode, CharSequence errString) {
165 super.onAuthenticationError(errorCode, errString);
166 Log.d(TAG, "Error message " + errorCode + ": " + errString);
167 Toast.makeText(context, context.getString(R.string.authenticate_fingerprint), Toast.LENGTH_LONG).show();
168 }
169 @Override
170 public void onAuthenticationHelp(int helpCode, CharSequence helpString) {
171 super.onAuthenticationHelp(helpCode, helpString);
172 Toast.makeText(context, R.string.auth_successful, Toast.LENGTH_LONG).show();
173 }
174 @Override
175 public void onAuthenticationSucceeded(FingerprintManager.AuthenticationResult result) {
176 super.onAuthenticationSucceeded(result);
177 userString = mPref.getUserData();
178 mUser = mGson.fromJson(userString, UserObject.class);
179 if(mUser != null){
180 Toast.makeText(context, context.getString(R.string.auth_successful), Toast.LENGTH_LONG).show();
181 if(mUser.isLoginOption()){
182 // login with fingerprint and password
183 showPasswordAuthentication(context);
184 }
185 else{
186 // login with only fingerprint
187 Intent userIntent = new Intent(context, UserProfileActivity.class);
188 userIntent.putExtra("USER_BIO", userString);
189 context.startActivity(userIntent);
190 }
191 }else{
192 Toast.makeText(context, "You must register before login with fingerprint", Toast.LENGTH_LONG).show();
193 }
194 }
195 @Override
196 public void onAuthenticationFailed() {
197 super.onAuthenticationFailed();
198 }
199 public void completeFingerAuthentication(FingerprintManager fingerprintManager, FingerprintManager.CryptoObject cryptoObject){
200 if (ActivityCompat.checkSelfPermission(context, Manifest.permission.USE_FINGERPRINT) != PackageManager.PERMISSION_GRANTED) {
201 return;
202 }
203 try{
204 fingerprintManager.authenticate(cryptoObject, new CancellationSignal(), 0, this, null);
205 }catch (SecurityException ex) {
206 Log.d(TAG, "An error occurred:\n" + ex.getMessage());
207 } catch (Exception ex) {
208 Log.d(TAG, "An error occurred\n" + ex.getMessage());
209 }
210 }
211 }
212 private static void showPasswordAuthentication(Context context){
213 final Dialog openDialog = new Dialog(context);
214 openDialog.setContentView(R.layout.password_layout);
215 openDialog.setTitle("Enter Password");
216 final EditText passwordDialog = (EditText)openDialog.findViewById(R.id.password);
217 Button loginWithPasswordButton = (Button)openDialog.findViewById(R.id.login_button);
218 loginWithPasswordButton.setOnClickListener(new View.OnClickListener() {
219 @Override
220 public void onClick(View view) {
221 String authPassword = passwordDialog.getText().toString();
222 if(TextUtils.isEmpty(authPassword)){
223 Toast.makeText(view.getContext(), "Password field must be filled", Toast.LENGTH_LONG).show();
224 return;
225 }
226 if(mUser.getPassword().equals(authPassword)){
227 Intent userIntent = new Intent(view.getContext(), UserProfileActivity.class);
228 userIntent.putExtra("USER_BIO", userString);
229 view.getContext().startActivity(userIntent);
230 }else{
231 Toast.makeText(view.getContext(), "Incorrect password! Try again", Toast.LENGTH_LONG).show();
232 return;
233 }
234 openDialog.dismiss();
235 }
236 });
237 openDialog.show();
238 }
239}