2

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) 
    } 

} 
+0

Das Stacktrace selbst ist wichtiger als die Fehlermeldung. Zumal dieser Fehler von einem anderen verursacht wird. Könnten Sie das bitte hinzufügen? – tynn

+0

@tynn Ich habe meine Frage bearbeitet – menefrego

+0

Sind Sie sicher, dass 'generateKey()' ohne Fehler aufgerufen wird? – BakaWaii

Antwort

0

Build-Version Reibe sein sollte als oder gleich Eibisch. wenn Sie weniger als M versuchen, dann kann es angehoben Fehler ..

+0

Ich weiß das und berücksichtigte es – menefrego

0

Sie null SecretKey Gießen die

val key = keyStore?.getKey(Constants.FINGERPRINT_KEY_NAME, null) as SecretKey 

Hier Nicht-NULL-Werte zulässt Sie könnten null erhalten, wenn keyStore null oder wenn getKey() Renditen null (wenn der angegebene Alias ​​nicht existiert oder keinen key-related-Eintrag identifiziert).

Also ist es völlig in Ordnung, dort null zu bekommen. Da Sie aufmuntern, könnten Sie sogar auf ClassCastException stoßen. Um dies zu verhindern, verwenden Sie stattdessen den typsicheren Cast Operator as?.

val key: SecretKey? = keyStore?.getKey(Constants.FINGERPRINT_KEY_NAME, null) as? SecretKey 
Verwandte Themen