Fingerprint authentication came with Android 6.0 (Marshmallow), with the newly released APIs allowing users to authenticate their smartphones with fingerprint sensors. In order to authenticate users using fingerprint sensors we need the instance of FingerprintManager class and call the authenticate() method. Also, we should take care of the devices that must have fingerprint sensors.
Advantages of using fingerprint authentication:
- Fast, Reliable, and Ease to use
- High security as each individual has unique fingerprints
- Most importantly, it doesn’t matter that you are physically or medically fit or not able to remember your password, fingerprints are always faultless
Example
In this example, we will build an application that asks for users’ fingerprints to authenticate and if the users enter the correct fingerprint then they are allowed to enter into the application.
Step by Step Implementation
Step 1: Create a new project
To create a new project in Android Studio please refer to How to Create/Start a New Project in Android Studio. Note that select Java as the programming language. Make sure while creating a new android project you set the minimum API level to be 23 (Android 6.0).
Step 2: Permission required
In order to use fingerprint authentication, we need to the permission USE_FINGERPRINT to our AndroidMainfest.xml file.
XML
<? xml version = "1.0" encoding = "utf-8" ?> < manifest > < uses-permission android:name = "android.permission.USE_FINGERPRINT" /> </ manifest > |
Before moving further let’s add some color attributes for our application in the colors.xml file.
XML
< resources > < color name = "colorPrimary" >#0F9D58</ color > < color name = "colorPrimaryDark" >#16E37F</ color > < color name = "colorAccent" >#03DAC5</ color > < color name = "black" >#000</ color > </ resources > |
Step 3: Creating image assets
In this step, we will create an image asset for fingerprint. Go to drawable > right-click > New > Vector Asset > Clip Art and search for fingerprint and add it to the drawable folder.
Step 4: Creating fingerprint layout
Now, we will create the layout for our fingerprint sensor. Go to activity_main.xml and copy the following code.
XML
<? xml version = "1.0" encoding = "utf-8" ?> < LinearLayout android:layout_width = "match_parent" android:layout_height = "match_parent" android:gravity = "center" android:orientation = "vertical" android:background = "@color/colorAccent" tools:context = ".MainActivity" > < ImageView android:layout_width = "72dp" android:layout_height = "72dp" android:layout_margin = "8dp" android:src = "@drawable/ic_fingerprint" /> < TextView android:layout_width = "wrap_content" android:layout_height = "wrap_content" android:gravity = "center" android:textColor = "#000" android:layout_margin = "8dp" android:text = "One Touch Sing In" /> < TextView android:layout_width = "wrap_content" android:layout_height = "wrap_content" android:gravity = "center" android:textColor = "#000" android:layout_margin = "8dp" android:text = "Please place user finger for authentication" /> < TextView android:id = "@+id/textMsg" android:textColor = "#000" android:layout_width = "match_parent" android:gravity = "center" android:textAppearance = "@style/TextAppearance.AppCompat.Large" android:layout_margin = "8dp" android:layout_height = "wrap_content" /> </ LinearLayout > |
Step 5: Working with MainActivity.java file
In this step, we will introduce our FingerprintManager class and initialize it. We will use generateKey() method which will generate an encryption key that is stored securely on the device, we will also use cipherInit() method which initialized the cipher that will be used to create the encrypted FingerprintManager. Below is the code for the MainActivity.java file.
Java
package com.paulsofts.gfgfingerprintauthentication; import androidx.appcompat.app.AppCompatActivity; import androidx.core.app.ActivityCompat; import android.Manifest; import android.annotation.TargetApi; import android.app.KeyguardManager; import android.content.pm.PackageManager; import android.hardware.fingerprint.FingerprintManager; import android.os.Build; import android.os.Bundle; import android.security.keystore.KeyGenParameterSpec; import android.security.keystore.KeyPermanentlyInvalidatedException; import android.security.keystore.KeyProperties; import android.widget.TextView; import java.io.IOException; import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; 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; public class MainActivity extends AppCompatActivity { private KeyStore keyStore; // Defining variable for storing // key in android keystore container private static final String KEY_NAME = "GEEKSFORGEEKS" ; private Cipher cipher; private TextView errorText; @Override protected void onCreate(Bundle savedInstanceState) { super .onCreate(savedInstanceState); setContentView(R.layout.activity_main); // Initializing KeyguardManager and FingerprintManager KeyguardManager keyguardManager = (KeyguardManager) getSystemService(KEYGUARD_SERVICE); FingerprintManager fingerprintManager = (FingerprintManager) getSystemService(FINGERPRINT_SERVICE); // Initializing our error text errorText = (TextView) findViewById(R.id.errorText); // Here, we are using various security checks // Checking device is inbuilt with fingerprint sensor or not if (!fingerprintManager.isHardwareDetected()){ // Setting error message if device // doesn't have fingerprint sensor errorText.setText( "Device does not support fingerprint sensor" ); } else { // Checking fingerprint permission if (ActivityCompat.checkSelfPermission( this , Manifest.permission.USE_FINGERPRINT) != PackageManager.PERMISSION_GRANTED) { errorText.setText( "Fingerprint authentication is not enabled" ); } else { // Check for at least one registered finger if (!fingerprintManager.hasEnrolledFingerprints()) { errorText.setText( "Register at least one finger" ); } else { // Checking for screen lock security if (!keyguardManager.isKeyguardSecure()) { errorText.setText( "Screen lock security not enabled" ); } else { // if everything is enabled and correct then we will generate // the encryption key which will be stored on the device generateKey(); if (cipherInit()) { FingerprintManager.CryptoObject cryptoObject = new FingerprintManager.CryptoObject(cipher); FingerprintHandler helper = new FingerprintHandler( this ); helper.startAuth(fingerprintManager, cryptoObject); } } } } } } @TargetApi (Build.VERSION_CODES.M) protected void generateKey() { try { keyStore = KeyStore.getInstance( "AndroidKeyStore" ); } catch (Exception e) { e.printStackTrace(); } KeyGenerator keyGenerator; try { keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore" ); } catch (NoSuchAlgorithmException | NoSuchProviderException e) { throw new RuntimeException( "KeyGenerator instance failed" , e); } try { keyStore.load( null ); keyGenerator.init( new KeyGenParameterSpec.Builder(KEY_NAME, KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT) .setBlockModes(KeyProperties.BLOCK_MODE_CBC) .setUserAuthenticationRequired( true ) .setEncryptionPaddings( KeyProperties.ENCRYPTION_PADDING_PKCS7) .build()); keyGenerator.generateKey(); } catch (NoSuchAlgorithmException | InvalidAlgorithmParameterException | CertificateException | IOException e) { throw new RuntimeException(e); } } @TargetApi (Build.VERSION_CODES.M) public boolean cipherInit() { try { cipher = Cipher.getInstance(KeyProperties.KEY_ALGORITHM_AES + "/" + KeyProperties.BLOCK_MODE_CBC + "/" + KeyProperties.ENCRYPTION_PADDING_PKCS7); } catch (NoSuchAlgorithmException | NoSuchPaddingException e) { throw new RuntimeException( "Cipher failed" , e); } try { keyStore.load( null ); SecretKey key = (SecretKey) keyStore.getKey(KEY_NAME, null ); cipher.init(Cipher.ENCRYPT_MODE, key); return true ; } catch (KeyPermanentlyInvalidatedException e) { return false ; } catch (KeyStoreException | CertificateException | UnrecoverableKeyException | IOException | NoSuchAlgorithmException | InvalidKeyException e) { throw new RuntimeException( "Cipher initialization failed" , e); } } } |
Step 6: Create Fingerprint Authentication Handler class
In this step, we will create a FingerprintHandler.java class and extends FingerprintManager.AuthenticationCallback and override the methods and provide our definitions. Below is the code of FingerpirntHandler class.
Java
import android.Manifest; import android.app.Activity; import android.content.Context; import android.content.pm.PackageManager; import android.hardware.fingerprint.FingerprintManager; import android.os.CancellationSignal; import android.widget.TextView; import androidx.core.app.ActivityCompat; import androidx.core.content.ContextCompat; public class FingerprintHandler extends FingerprintManager.AuthenticationCallback { private Context context; // Constructor public FingerprintHandler(Context mContext) { context = mContext; } // Fingerprint authentication starts here.. public void Authentication(FingerprintManager manager, FingerprintManager.CryptoObject cryptoObject) { CancellationSignal cancellationSignal = new CancellationSignal(); if (ActivityCompat.checkSelfPermission(context, Manifest.permission.USE_FINGERPRINT) != PackageManager.PERMISSION_GRANTED) { return ; } manager.authenticate(cryptoObject, cancellationSignal, 0 , this , null ); } // On authentication failed @Override public void onAuthenticationFailed() { this .update( "Authentication Failed!!!" , false ); } // On successful authentication @Override public void onAuthenticationSucceeded(FingerprintManager.AuthenticationResult result) { this .update( "Successfully Authenticated..." , true ); } // This method is used to update the text message // depending on the authentication result public void update(String e, Boolean success){ TextView textView = (TextView) ((Activity)context).findViewById(R.id.textMsg); textView.setText(e); if (success){ textView.setTextColor(ContextCompat.getColor(context,R.color.black)); } } } |
Output:
We will test our application on a device that supports a fingerprint sensor. Here, firstly we entered the incorrect finger and we get the Authentication failed message, and then we will enter the correct finger.