7

When I try to run a sample app for fingerprint authentication, the following exception is thrown.

The devices I've tried are:

Samsung S5 (Android 6.0.1 API 23)

07-08 03:31:57.796 30558-30558/com.netfinitymedia.notubeapp W/System.err: java.security.InvalidAlgorithmParameterException: java.lang.IllegalStateException: At least one fingerprint must be enrolled to create keys requiring user authentication for every use
07-08 03:31:57.796 30558-30558/com.netfinitymedia.notubeapp W/System.err:     at android.security.keystore.AndroidKeyStoreKeyGeneratorSpi.engineInit(AndroidKeyStoreKeyGeneratorSpi.java:238)
07-08 03:31:57.796 30558-30558/com.netfinitymedia.notubeapp W/System.err:     at android.security.keystore.AndroidKeyStoreKeyGeneratorSpi$AES.engineInit(AndroidKeyStoreKeyGeneratorSpi.java:53)
07-08 03:31:57.796 30558-30558/com.netfinitymedia.notubeapp W/System.err:     at javax.crypto.KeyGenerator.init(KeyGenerator.java:189)
07-08 03:31:57.796 30558-30558/com.netfinitymedia.notubeapp W/System.err:     at com.netfinitymedia.notubeapp.authentication.VerificationActivity.generateKey(VerificationActivity.java:177)
07-08 03:31:57.796 30558-30558/com.netfinitymedia.notubeapp W/System.err:     at com.netfinitymedia.notubeapp.authentication.VerificationActivity.initialize(VerificationActivity.java:131)
07-08 03:31:57.796 30558-30558/com.netfinitymedia.notubeapp W/System.err:     at com.netfinitymedia.notubeapp.authentication.VerificationActivity.onCreate(VerificationActivity.java:63)
07-08 03:31:57.796 30558-30558/com.netfinitymedia.notubeapp W/System.err:     at android.app.Activity.performCreate(Activity.java:6876)
07-08 03:31:57.796 30558-30558/com.netfinitymedia.notubeapp W/System.err:     at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1135)
07-08 03:31:57.796 30558-30558/com.netfinitymedia.notubeapp W/System.err:     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3206)
07-08 03:31:57.796 30558-30558/com.netfinitymedia.notubeapp W/System.err:     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3349)
07-08 03:31:57.796 30558-30558/com.netfinitymedia.notubeapp W/System.err:     at android.app.ActivityThread.access$1100(ActivityThread.java:221)
07-08 03:31:57.796 30558-30558/com.netfinitymedia.notubeapp W/System.err:     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1794)
07-08 03:31:57.796 30558-30558/com.netfinitymedia.notubeapp W/System.err:     at android.os.Handler.dispatchMessage(Handler.java:102)
07-08 03:31:57.796 30558-30558/com.netfinitymedia.notubeapp W/System.err:     at android.os.Looper.loop(Looper.java:158)
07-08 03:31:57.796 30558-30558/com.netfinitymedia.notubeapp W/System.err:     at android.app.ActivityThread.main(ActivityThread.java:7224)
07-08 03:31:57.796 30558-30558/com.netfinitymedia.notubeapp W/System.err:     at java.lang.reflect.Method.invoke(Native Method)
07-08 03:31:57.796 30558-30558/com.netfinitymedia.notubeapp W/System.err:     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230)
07-08 03:31:57.796 30558-30558/com.netfinitymedia.notubeapp W/System.err:     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120)
07-08 03:31:57.796 30558-30558/com.netfinitymedia.notubeapp W/System.err: Caused by: java.lang.IllegalStateException: At least one fingerprint must be enrolled to create keys requiring user authentication for every use
07-08 03:31:57.796 30558-30558/com.netfinitymedia.notubeapp W/System.err:     at android.security.keystore.KeymasterUtils.addUserAuthArgs(KeymasterUtils.java:115)
07-08 03:31:57.796 30558-30558/com.netfinitymedia.notubeapp W/System.err:     at android.security.keystore.AndroidKeyStoreKeyGeneratorSpi.engineInit(AndroidKeyStoreKeyGeneratorSpi.java:234)
07-08 03:31:57.796 30558-30558/com.netfinitymedia.notubeapp W/System.err:   ... 17 more
Pang
  • 9,564
  • 146
  • 81
  • 122
Daoud Shaheen
  • 364
  • 4
  • 16
  • 1
    https://github.com/googlesamples/android-FingerprintDialog/issues/18 –  Jul 08 '17 at 00:44

3 Answers3

3

You should use the fingerprint manager to check if a fingerprint reader exists and if the app has permission to use it before trying to generate a key.

_fingerprintManager = (FingerprintManager) _context.getSystemService(FINGERPRINT_SERVICE);

public boolean fingerprintEnabled()
{
    if (!_fingerprintManager.isHardwareDetected())
    {
        // Device doesn't support fingerprint authentication
        return false;
    }
    else if (ActivityCompat.checkSelfPermission(_context, Manifest.permission.USE_FINGERPRINT) != PackageManager.PERMISSION_GRANTED)
    {
        return false;
    }
    else if (!_keyguardManager.isKeyguardSecure())
    {
        return false;
    }
    else if (!_fingerprintManager.hasEnrolledFingerprints())
    {
        // User hasn't enrolled any fingerprints to authenticate with
        return false;
    }
    else
    {
        // Everything is ready for fingerprint authentication
        return true;
    }
}
Lysandus
  • 764
  • 4
  • 23
1

As the documentation says, now with BiometricManager, we can use the canAuthenticate function to check if the authenticator meets the given requirements. Be careful with the combination of authentications types!

val biometricManager = BiometricManager.from(this)
when (biometricManager.canAuthenticate(BIOMETRIC_STRONG or DEVICE_CREDENTIAL))
Jaco
  • 923
  • 2
  • 14
  • 28
0

This is more a workaround. I hope it will help you and other people outside:

Timber.d("checkForBiometrics started")
val fingerprintManagerCompat = FingerprintManagerCompat.from(activity!!)
val pm = context!!.packageManager
val canAuthenticate: Boolean
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
    val hasFingerprint = pm.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)
    val hasFace = pm.hasSystemFeature(PackageManager.FEATURE_FACE)
    val hasIris = pm.hasSystemFeature(PackageManager.FEATURE_IRIS)
    if(hasFingerprint && hasFace || hasFingerprint && hasIris) {
        Timber.d("checkForBiometrics has fingerprint and has face or iris")
        canAuthenticate = fingerprintManagerCompat.hasEnrolledFingerprints()
    } else if(hasFace || hasFingerprint) {
        Timber.d("checkForBiometrics has only face or only fingerprint")
        canAuthenticate = Biometric(activity!!).isAvailable()
    }
    else {
        canAuthenticate = false
    }
} else {
    canAuthenticate = false
}

return canAuthenticate

This will accept only fingerprint authentication, if device has more biometric options.

NullPointer
  • 1,250
  • 2
  • 12
  • 17