Android Keystore? .getKey devuelve null en algunos dispositivos

Estoy implementando la authentication de huellas digitales en mi aplicación. Enfrenté el problema de que no funciona correctamente en algunos dispositivos y mi aplicación falla. Sin embargo, también funciona en algunos dispositivos. El problema está en esta línea

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

El LogCat dice:

  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) 

Aquí está mi código completo:

 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) .setUserAuthenticationRequinetworking(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) } } 

La versión de compilation debe ser mayor o igual a malvavisco. si intenta less de M, puede generar un error …

Estás lanzando null a SecretKey que no SecretKey nulos

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

Aquí podría get un valor nulo cuando keyStore sea ​​nulo o si getKey() devuelve nulo (si el alias dado no existe o no identifica una input relacionada con la key).

Por lo tanto, está perfectamente bien anular allí. Dado que estás reubicando, incluso podrías toparte con una ClassCastException . Para evitar esto, simplemente use el operador de conversión de tipo seguro as? en lugar.

 val key: SecretKey? = keyStore?.getKey(Constants.FINGERPRINT_KEY_NAME, null) as? SecretKey 
  • No se pueden crear classs privadas con el mismo nombre en diferentes modules
  • Consultar datos de Google Spreadsheet en Android
  • cómo inicializar correctamente el recurso compartido en kotlintest 2.x (interceptSpec)
  • Errores de extensión de Kotlin
  • De la documentation de kotlin no está claro para mí el operador como
  • Dagger2 @Nullable anotación con Kotlin
  • Filtrar una subcadena en kotlin
  • Divida una cadena por un número fijo de caracteres
  • Evento táctil de interceptación y networkingirigirlo en function del estado del evento de movimiento
  • "Nombre de campo BSON no válido" durante la inserción
  • ¿Las coroutines de kotlin tienen llamada asincrónica con timer?