How to Implement Secure Fingerprint Login on Android with BiometricPrompt and Keystore
This article walks through implementing fingerprint login on Android, covering the legacy FingerprintManager API, the newer BiometricPrompt, integrating with Android Keystore for secure encryption, handling compatibility, UI considerations, and security best practices, complete with code examples and deployment results.
1. Introduction
Fingerprint login is a common method in finance apps; we added it to the Huolala driver Android app to improve user experience and reduce SMS costs. Google provides fingerprint APIs starting from Android 6.0.
2. Fingerprint Recognition
From Android 6.0 (API23) the system supports fingerprint via FingerprintManager. The API allows checking hardware, enrolled fingerprints, starting authentication, cancelling, and receiving callbacks. From Android 9.0 (API28) FingerprintManager is deprecated in favor of BiometricPrompt, which supports multiple biometrics but currently only fingerprint on most devices and enforces a standard UI.
2.1 FingerprintManager
Steps to use FingerprintManager:
① Request fingerprint permission
<!-- Android 6.0 enable touch sensor and identity authentication permission -->
<uses-permission android:name="android.permission.USE_FINGERPRINT"/>② Check if fingerprint is supported
isHardwareDetected() – hardware support
isKeyguardSecure() – lock screen set
hasEnrolledFingerprints() – at least one fingerprint enrolled
/**
* Determine if fingerprint is supported
*/
public static boolean supportFingerprint(Context context) {
if (VERSION.SDK_INT < 23) {
// System version too low
return false;
} else {
KeyguardManager km = context.getSystemService(KeyguardManager.class);
FingerprintManagerCompat fm = FingerprintManagerCompat.from(context);
if (!fm.isHardwareDetected()) {
return false;
} else if (!km.isKeyguardSecure()) {
return false;
} else if (!fm.hasEnrolledFingerprints()) {
return false;
}
}
return true;
}③ Start authentication
@RequiresApi(api = Build.VERSION_CODES.M)
public void authenticate(FingerprintManager.CryptoObject cryptoObject,
CancellationSignal cancellationSignal,
int flag,
FingerprintManager.AuthenticationCallback authenticationCallback,
Handler handler) {
if (fingerprintManager != null) {
fingerprintManager.authenticate(cryptoObject, cancellationSignal, flag, authenticationCallback, handler);
}
}Authentication callbacks include onAuthenticationFailed, onAuthenticationSucceeded, onAuthenticationHelp, and onAuthenticationError. The event flow is: start → (help/failed)* → succeeded/error.
④ Cancel authentication
/**
* Stop listening
*/
public void cancelListening() {
if (cancellationSignal != null) {
cancellationSignal.cancel();
}
}2.2 BiometricPrompt
Differences from FingerprintManager:
Add dependency: implementation "androidx.biometric:biometric:1.1.0" Request biometric permission:
<!-- Android 9.0 biometric permission -->
<uses-permission android:name="android.permission.USE_BIOMETRIC"/>③ Launch authentication
BiometricPrompt.PromptInfo promptInfo = new BiometricPrompt.PromptInfo.Builder()
.setTitle("Fingerprint verification")
.setDescription("User fingerprint verification")
.setNegativeButtonText("Cancel")
.build();
getPrompt().authenticate(promptInfo);
private BiometricPrompt getPrompt() {
Executor executor = ContextCompat.getMainExecutor(this);
BiometricPrompt.AuthenticationCallback callback = new BiometricPrompt.AuthenticationCallback() {
@Override
public void onAuthenticationSucceeded(@NonNull BiometricPrompt.AuthenticationResult result) {
// success
}
@Override
public void onAuthenticationFailed() {
// failure
}
@Override
public void onAuthenticationError(int errorCode, @NonNull CharSequence errString) {
// error
}
};
return new BiometricPrompt(this, executor, callback);
}④ UI – system dialog cannot be customized; example on Honor X8:
Limitations: only success/failure is returned, no account binding, and root/hook attacks can bypass authentication.
2.3 Android Keystore
Android Keystore stores keys in a secure container (TEE). Keys can be used for encryption without being exported. Combining Keystore with fingerprint ensures the key is usable only after successful biometric authentication.
Steps:
① Create KeyStore instance
KeyStore keystore = KeyStore.getInstance(KEYSTORE_NAME);
keystore.load(null);② Generate AES key with user authentication required
@RequiresApi(api = Build.VERSION_CODES.M)
public void createKey() throws Exception {
KeyGenerator keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, KEYSTORE_NAME);
KeyGenParameterSpec.Builder builder = new KeyGenParameterSpec.Builder(DEFAULT_KEY_NAME,
KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
.setBlockModes(KeyProperties.BLOCK_MODE_CBC)
.setUserAuthenticationRequired(true)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7);
keyGenerator.init(builder.build());
keyGenerator.generateKey();
}③ Initialize Cipher with the key to obtain CryptoObject
public Cipher createCipher() throws Exception {
SecretKey key = (SecretKey) keyStore.getKey(DEFAULT_KEY_NAME, null);
Cipher cipher = Cipher.getInstance(
KeyProperties.KEY_ALGORITHM_AES + "/" + KeyProperties.BLOCK_MODE_CBC + "/" + KeyProperties.ENCRYPTION_PADDING_PKCS7);
cipher.init(Cipher.ENCRYPT_MODE, key);
return cipher;
}④ Start fingerprint authentication with the CryptoObject
CryptoObjectHelper cryptoObjectHelper = new CryptoObjectHelper();
if (cancellationSignal == null) {
cancellationSignal = new CancellationSignal();
}
fingerprintManager.authenticate(
cryptoObjectHelper.buildCryptoObject(),
0,
cancellationSignal,
myAuthCallback,
null);⑤ In onAuthenticationSucceeded, retrieve the Cipher and perform encryption
@Override
public void onSucceeded(FingerprintManager.AuthenticationResult result) {
try {
Cipher cipher = result.getCryptoObject().getCipher();
byte[] bytes = cipher.doFinal(pwd.getBytes());
aCache.put("pwdEncode", Base64.encodeToString(bytes, Base64.URL_SAFE));
byte[] iv = cipher.getIV();
aCache.put("iv", Base64.encodeToString(iv, Base64.URL_SAFE));
} catch (Exception e) {
e.printStackTrace();
}
}3. Fingerprint Login
Fingerprint login replaces password entry by encrypting login data locally with a key protected by biometric authentication.
3.1 Enable Fingerprint Login
Process: after a normal login, enable fingerprint, compare stored fingerprints (kept locally), and store a private key in Keystore; the public key is uploaded for server verification.
3.2 Use Fingerprint Login
When logging in, retrieve encrypted data, send to server for decryption and verification.
Additional measures: one‑time authorization code and signature with a client‑side private key bound to biometric authentication.
4. Compatibility
4.1 Version Compatibility
Fingerprint APIs are available from Android 6.0. Below that, manufacturers may provide proprietary SDKs. FingerprintManager is deprecated after Android 9.0; developers should handle both FingerprintManagerCompat and BiometricPrompt checks.
4.2 UI Compatibility
FingerprintManagerallows custom UI, while BiometricPrompt uses a system dialog whose appearance varies across manufacturers.
5. Security
Rooted devices can bypass fingerprint verification. Using Android Keystore to generate a key and passing it as CryptoObject ensures the key is usable only after successful biometric authentication.
Google’s API does not expose fingerprint IDs, so binding a fingerprint to a specific account is not possible; new fingerprints added later can also unlock the same account.
Some low‑level methods to obtain fingerprint IDs are blocked by @UnsupportedAppUsage.
Third‑party solutions such as Tencent’s SOTER and Alibaba’s IFAA provide hardware‑rooted keys stored in TEE, improving security for high‑risk scenarios like payments.
6. Deployment Results
After release, the fingerprint login feature ran on Honor 8X devices, as shown in the screenshots:
7. Summary
Since launch, many drivers have enabled fingerprint login, improving user experience and reducing SMS verification costs by about 20%. Sharing the implementation details helps other developers avoid pitfalls.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
