2017-11-02 30 views
2

내 애플리케이션에서 지문 인증을 구현 중입니다. in이 일부 장치에서 제대로 작동하지 않고 응용 프로그램이 손상되는 문제에 직면했습니다. 그럼에도 불구하고 일부 기기에서도 작동합니다. 문제는Android 키 스토어 .getKey가 일부 기기에서 null을 반환합니다.

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

로그 캣 말씀이 줄 수 있습니다 :

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 미만 노력하면 는 오류를 제기 할 수 있습니다 .. 당신은 널 캐스팅하고

+0

나는 이것을 알고 그것을 고려했다. – menefrego

0

비 - 널 (NULL) SecretKey에 여기

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

keyStore가 null 또는 getKey() 반환하는 경우 때 널 (null)을 얻을 수 null (지정된 별명이 존재하지 않는지, 키 관련 엔트리를 식별하지 않는 경우)

그래서 null 값을 얻는 것이 완벽합니다. 상영 중이기 때문에 ClassCastException에 들어갈 수도 있습니다. 이를 방지하려면 형식 안전 캐스팅 연산자 as?을 대신 사용하십시오.

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