Ich implementiere Fingerabdruck-Authentifizierung in meiner Anwendung. Ich habe das Problem, dass auf einigen Geräten nicht richtig funktioniert und meine Anwendung abstürzt. Trotzdem funktioniert es auch auf einigen Geräten. Das Problem ist in dieser ZeileAndroid Keystore? .getKey gibt auf einigen Geräten null zurück
val key = keyStore?.getKey(Constants.FINGERPRINT_KEY_NAME, null) as SecretKey
Die LogCat sagt:
11-02 14:27:42.825 E: FATAL EXCEPTION: main
Process: kyivenergo.ua.kyivenegro, PID: 2298
java.lang.RuntimeException: Unable to start activity ComponentInfo{kyivenergo.ua.kyivenegro/ua.dtec.appOk.ui.screens.splash.SplashScreenActivity}: kotlin.TypeCastException: null cannot be cast to non-null type javax.crypto.SecretKey
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2646)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2707)
at android.app.ActivityThread.-wrap12(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1460)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6077)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:866)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:756)
Caused by: kotlin.TypeCastException: null cannot be cast to non-null type javax.crypto.SecretKey
at ua.dtec.appOk.ui.dialog.FingerprintDialog.initCipher(FingerprintDialog.kt:222)
at ua.dtec.appOk.ui.dialog.FingerprintDialog.doCheck(FingerprintDialog.kt:147)
at ua.dtec.appOk.ui.dialog.FingerprintDialog.show(FingerprintDialog.kt:65)
at ua.dtec.appOk.ui.screens.splash.SplashScreenActivity.showFingerprintDialog(SplashScreenActivity.kt:55)
at ua.dtec.appOk.ui.screens.splash.SplashScreenActivity.onStart(SplashScreenActivity.kt:33)
at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1248)
at android.app.Activity.performStart(Activity.java:6679)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2609)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2707)
at android.app.ActivityThread.-wrap12(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1460)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6077)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:866)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:756)
Hier ist meine vollständige Code:
private fun doCheck() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
keyguardManager =
c.getSystemService(KEYGUARD_SERVICE) as KeyguardManager
fingerprintManager =
c.getSystemService(FINGERPRINT_SERVICE) as FingerprintManager
if (!fingerprintManager!!.isHardwareDetected()) {
Toast.makeText(c, R.string.dialog_fingerprint_no_hardware_toast, Toast.LENGTH_SHORT).show()
}
if (ActivityCompat.checkSelfPermission(c, Manifest.permission.USE_FINGERPRINT) != PackageManager.PERMISSION_GRANTED) {
Toast.makeText(c, R.string.dialog_fingerprint_enable_fingerprint_permission, Toast.LENGTH_SHORT).show()
}
if (!fingerprintManager!!.hasEnrolledFingerprints()) {
Toast.makeText(c, R.string.dialog_fingerprint_no_fingerprints, Toast.LENGTH_SHORT).show()
}
if (!keyguardManager?.isKeyguardSecure()!!) {
Toast.makeText(c, R.string.dialog_fingerprint_no_lock_screen, Toast.LENGTH_SHORT).show()
} else {
generateKey()
}
if (initCipher()) {
cryptoObject = FingerprintManager.CryptoObject(cipher)
helper = FingerPrintHelper(dialog!!)
helper?.FingerprintHandler(c)
helper?.startAuth(fingerprintManager!!, cryptoObject!!)
}
}
}
private fun generateKey() {
try {
keyStore = KeyStore.getInstance("AndroidKeyStore")
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore")
keyStore?.load(null)
keyGenerator!!.init(
KeyGenParameterSpec.Builder(Constants.FINGERPRINT_KEY_NAME,
KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT)
.setBlockModes(KeyProperties.BLOCK_MODE_CBC)
.setUserAuthenticationRequired(true)
.setEncryptionPaddings(
KeyProperties.ENCRYPTION_PADDING_PKCS7)
.build())
}
keyGenerator?.generateKey()
} catch (exc: KeyStoreException) {
exc.printStackTrace()
throw FingerprintException(exc)
} catch (exc: NoSuchAlgorithmException) {
exc.printStackTrace()
throw FingerprintException(exc)
} catch (exc: NoSuchProviderException) {
exc.printStackTrace()
throw FingerprintException(exc)
} catch (exc: InvalidAlgorithmParameterException) {
exc.printStackTrace()
throw FingerprintException(exc)
} catch (exc: CertificateException) {
exc.printStackTrace()
throw FingerprintException(exc)
} catch (exc: IOException) {
exc.printStackTrace()
throw FingerprintException(exc)
}
}
@RequiresApi(Build.VERSION_CODES.M)
fun initCipher(): Boolean {
try {
cipher = Cipher.getInstance(
KeyProperties.KEY_ALGORITHM_AES + "/"
+ KeyProperties.BLOCK_MODE_CBC + "/"
+ KeyProperties.ENCRYPTION_PADDING_PKCS7)
} catch (e: NoSuchAlgorithmException) {
throw RuntimeException("Failed to get Cipher", e)
} catch (e: NoSuchPaddingException) {
throw RuntimeException("Failed to get Cipher", e)
}
try {
keyStore?.load(
null)
val key = keyStore?.getKey(Constants.FINGERPRINT_KEY_NAME, null) as SecretKey
cipher?.init(Cipher.ENCRYPT_MODE, key)
return true
} catch (e: KeyPermanentlyInvalidatedException) {
return false
} catch (e: KeyStoreException) {
throw RuntimeException("Failed to init Cipher", e)
} catch (e: CertificateException) {
throw RuntimeException("Failed to init Cipher", e)
} catch (e: UnrecoverableKeyException) {
throw RuntimeException("Failed to init Cipher", e)
} catch (e: IOException) {
throw RuntimeException("Failed to init Cipher", e)
} catch (e: NoSuchAlgorithmException) {
throw RuntimeException("Failed to init Cipher", e)
} catch (e: InvalidKeyException) {
throw RuntimeException("Failed to init Cipher", e)
}
}
Das Stacktrace selbst ist wichtiger als die Fehlermeldung. Zumal dieser Fehler von einem anderen verursacht wird. Könnten Sie das bitte hinzufügen? – tynn
@tynn Ich habe meine Frage bearbeitet – menefrego
Sind Sie sicher, dass 'generateKey()' ohne Fehler aufgerufen wird? – BakaWaii