2

私のアプリケーションで指紋認証を実装しています。私はinがいくつかのデバイスで正しく動作せず、アプリケーションがクラッシュするという問題に直面しました。それにもかかわらず、いくつかのデバイスでも動作します。問題は、この行にAndroidキーストア?getKeyは一部のデバイスでnullを返します

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

でLogCatは言う:ここ

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)  

は私の完全なコードです:

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

スタックトレース自体がエラーメッセージよりも重要です。特に、このエラーは別のエラーの原因です。あなたはそれを追加できますか? – tynn

+0

@tynn私の質問を編集しました – menefrego

+0

'generateKey()'は何のエラーもなく呼び出されますか? – BakaWaii

答えて

0

ビルドバージョンは、よりおろし金やマシュマロと同じでなければなりません。あなたはその後、M未満をしようとした場合 はエラーを上げることができます..あなたがnullキャストしている

+0

私はこれを知って、それを考慮に入れました – menefrego

0

を非NULL可能であるSecretKeyにここ

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

keyStoreがnullまたはgetKey()返す場合のときにはnullを得ることができますnull(指定されたエイリアスが存在しないか、キー関連のエントリを識別しない場合)

だから、そこにヌルを入れるのは大丈夫です。アップキャストしているので、ClassCastExceptionに入ることさえあります。これを防ぐには、タイプセーフキャスト演算子as?を代わりに使用してください。

val key: SecretKey? = keyStore?.getKey(Constants.FINGERPRINT_KEY_NAME, null) as? SecretKey 
関連する問題