java.lang.IllegalArgumentException:加密不支持设备凭证

克韦塔诺夫斯卡

我正在尝试设置BiometricPrompt,但是我需要使用CryptoObject进行身份验证,这在https://developer.android.com/reference/android/hardware/biometrics/BiometricPrompt.Builder.html#看来是不可能的setDeviceCredentialAllowed(boolean)设置为true。

try {
      KeyGeneratorUtil.generateKeyPair("1", null);
    } catch (Exception e) {
      e.printStackTrace();
    }

    PrivateKey privateKey;
    try {
      privateKey = KeyGeneratorUtil.getPrivateKeyReference("test");
    } catch (Exception e) {
      return;
    }

    final Signature signature;
    try {
      signature = initSignature(privateKey);
    } catch (Exception e) {
      return;
    }
final BiometricPrompt.CryptoObject cryptoObject = new BiometricPrompt.CryptoObject(signature);

final BiometricPrompt biometricPrompt = new BiometricPrompt.Builder(context)
        .setTitle("Title")
        .setDescription("Description")
        .setDeviceCredentialAllowed(true)
        .build();

...

biometricPrompt.authenticate(cryptoObject, new CancellationSignal(), executor, callback);

运行此命令时,出现以下异常。

2019-07-03 13:50:45.140 13715-13715/kcvetano.com.biometricpromptpoc E/AndroidRuntime: FATAL EXCEPTION: main
    Process: kcvetano.com.biometricpromptpoc, PID: 13715
    java.lang.IllegalArgumentException: Device credential not supported with crypto
        at android.hardware.biometrics.BiometricPrompt.authenticate(BiometricPrompt.java:556)
        at kcvetano.com.biometricpromptpoc.BiometryAPI29.handleBiometry(BiometryAPI29.java:65)
        at kcvetano.com.biometricpromptpoc.MainActivity$1.onClick(MainActivity.java:56)
        at android.view.View.performClick(View.java:7251)
        at android.view.View.performClickInternal(View.java:7228)
        at android.view.View.access$3500(View.java:802)
        at android.view.View$PerformClick.run(View.java:27843)
        at android.os.Handler.handleCallback(Handler.java:883)
        at android.os.Handler.dispatchMessage(Handler.java:100)
        at android.os.Looper.loop(Looper.java:214)
        at android.app.ActivityThread.main(ActivityThread.java:7116)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:925)
simne7

这应该可以解决问题:

biometricPrompt.authenticate(null, new CancellationSignal(), executor, callback);

错误消息中或多或少都写有(可能会说是隐藏的):setDeviceCredentialAllowed(true)使用时不要使用加密对象。

一切都分解为您如何CryptoObject配置内部加密操作的私钥

我假设用于初始化签名对象的私钥是使用构建的setUserAuthenticationRequired(true)使用该选项构建的密钥只能用于一个加密操作。此外,还必须使用BiometricPrompt.authenticateFingerprintManager.authenticate(现在不推荐使用BiometricPrompt)使用生物识别技术将其解锁

官方文件谈到,如果钥匙被授权,如果用户已被认证的前提下使用,即两种模式:

  • 内置的密钥setUserAuthenticationRequired(true)必须使用FingerprintManager.authenticate(现在BiometricPrompt.authenticate解锁
  • 内置的密钥setUserAuthenticationValidityDurationSeconds必须随KeyguardManager.createConfirmDeviceCredentialIntent流程解锁

在年底的说明官方的生物特征身份验证培训指导建议,从交换机KeyguardManager.createConfirmDeviceCredentialIntent流向新BiometricPromptsetDeviceCredentialAllowed(true)

但这并不像将密钥的UserAuthenticationValidityDuration设置为非零值那样简单,因为这将UserNotAuthenticatedExceptioninitSignature(privateKey)初始化签名对象后立即触发内部调用。还有更多警告...请参见下面的两个示例


生物特征密钥验证

fun biometric_auth() {

    val myKeyStore = KeyStore.getInstance("AndroidKeyStore")
    myKeyStore.load(null)

    val keyGenerator = KeyPairGenerator.getInstance(
        KeyProperties.KEY_ALGORITHM_EC,
        "AndroidKeyStore"
    )

    // build MY_BIOMETRIC_KEY
    val keyAlias = "MY_BIOMETRIC_KEY"
    val keyProperties = KeyProperties.PURPOSE_SIGN or KeyProperties.PURPOSE_VERIFY
    val builder = KeyGenParameterSpec.Builder(keyAlias, keyProperties)
        .setAlgorithmParameterSpec(ECGenParameterSpec("secp256r1"))
        .setDigests(KeyProperties.DIGEST_SHA256)
        .setUserAuthenticationRequired(true)


    keyGenerator.run {
        initialize(builder.build())
        generateKeyPair()
    }

    val biometricKeyEntry: KeyStore.Entry = myKeyStore.getEntry(keyAlias, null)
    if (biometricKeyEntry !is KeyStore.PrivateKeyEntry) {
        return
    }

    // create signature object
    val signature = Signature.getInstance("SHA256withECDSA")
    // init signature else "IllegalStateException: Crypto primitive not initialized" is thrown
    signature.initSign(biometricKeyEntry.privateKey)
    val cryptoObject = BiometricPrompt.CryptoObject(signature)

    // create biometric prompt
    // NOTE: using androidx.biometric.BiometricPrompt here
    val prompt = BiometricPrompt(
        this,
        AsyncTask.THREAD_POOL_EXECUTOR,
        object : BiometricPrompt.AuthenticationCallback() {
            // override the required methods...
            override fun onAuthenticationError(errorCode: Int, errString: CharSequence) {
                super.onAuthenticationError(errorCode, errString)
                Log.w(TAG, "onAuthenticationError $errorCode $errString")
            }

            override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult) {
                super.onAuthenticationSucceeded(result)
                Log.d(TAG, "onAuthenticationSucceeded" + result.cryptoObject)
                val sigBytes = signature.run {
                    update("hello world".toByteArray())
                    sign()
                }
                Log.d(TAG, "sigStr " + Base64.encodeToString(sigBytes, 0))
            }

            override fun onAuthenticationFailed() {
                super.onAuthenticationFailed()
                Log.w(TAG, "onAuthenticationFailed")
            }
        })
    val promptInfo = BiometricPrompt.PromptInfo.Builder()
        .setTitle("Unlock your device")
        .setSubtitle("Please authenticate to ...")
        // negative button option required for biometric auth
        .setNegativeButtonText("Cancel")
        .build()
    prompt.authenticate(promptInfo, cryptoObject)
}


PIN /密码/图案验证

fun password_auth() {

    val myKeyStore = KeyStore.getInstance("AndroidKeyStore")
    myKeyStore.load(null)

    val keyGenerator = KeyPairGenerator.getInstance(
        KeyProperties.KEY_ALGORITHM_EC,
        "AndroidKeyStore"
    )

    // build MY_PIN_PASSWORD_PATTERN_KEY
    val keyAlias = "MY_PIN_PASSWORD_PATTERN_KEY"
    val keyProperties = KeyProperties.PURPOSE_SIGN or KeyProperties.PURPOSE_VERIFY
    val builder = KeyGenParameterSpec.Builder(keyAlias, keyProperties)
        .setAlgorithmParameterSpec(ECGenParameterSpec("secp256r1"))
        .setDigests(KeyProperties.DIGEST_SHA256)
        // this would trigger an UserNotAuthenticatedException: User not authenticated when using the fingerprint
        // .setUserAuthenticationRequired(true)
        .setUserAuthenticationValidityDurationSeconds(10)


    keyGenerator.run {
        initialize(builder.build())
        generateKeyPair()
    }

    val keyEntry: KeyStore.Entry = myKeyStore.getEntry(keyAlias, null)
    if (keyEntry !is KeyStore.PrivateKeyEntry) {
        return
    }

    // create signature object
    val signature = Signature.getInstance("SHA256withECDSA")
    // this would fail with UserNotAuthenticatedException: User not authenticated
    // signature.initSign(keyEntry.privateKey)

    // create biometric prompt
    // NOTE: using androidx.biometric.BiometricPrompt here
    val prompt = BiometricPrompt(
        this,
        AsyncTask.THREAD_POOL_EXECUTOR,
        object : BiometricPrompt.AuthenticationCallback() {
            // override the required methods...
            override fun onAuthenticationError(errorCode: Int, errString: CharSequence) {
                super.onAuthenticationError(errorCode, errString)
                Log.w(TAG, "onAuthenticationError $errorCode $errString")
            }

            override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult) {
                super.onAuthenticationSucceeded(result)
                Log.d(TAG, "onAuthenticationSucceeded " + result.cryptoObject)
                // now it's safe to init the signature using the password key
                signature.initSign(keyEntry.privateKey)
                val sigBytes = signature.run {
                    update("hello password/pin/pattern".toByteArray())
                    sign()
                }
                Log.d(TAG, "sigStr " + Base64.encodeToString(sigBytes, 0))
            }

            override fun onAuthenticationFailed() {
                super.onAuthenticationFailed()
                Log.w(TAG, "onAuthenticationFailed")
            }
        })
    val promptInfo = BiometricPrompt.PromptInfo.Builder()
        .setTitle("Unlock your device")
        .setDeviceCredentialAllowed(true)
        .build()
    prompt.authenticate(promptInfo)
}

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

XMLDecoder >> java.lang.IllegalArgumentException:不支持的元素

Couchbase 的 Spring Data - java.lang.IllegalArgumentException:JsonArray 不支持的类型:

Cloud Firestore java.lang.IllegalArgumentException:数据无效。不支持的类型:

java.lang.IllegalArgumentException:AppCompat不支持当前的主题功能

java.lang.IllegalArgumentException:不支持的类文件主要版本58

Android dexguard java.lang.IllegalArgumentException:类类不支持元数据注册

致命异常:java.lang.UnsupportedOperationException:不支持短信

JNI不支持的参数类型java.lang.StringBuilder

异常:java.sql.SQLDataException:不支持从TIMESTAMP到java.lang.Long的转换

java.lang.RuntimeException:不支持的文字类型类org.joda.time.DateTime

我无法解决java.lang.UnsupportedOperationException:尚不支持

如何修复java.lang.UnsupportedClassVersionError:不支持的major.minor版本

java.lang.UnsupportedOperationException:不支持的服务:可访问性android studio

Maven / Jenkins java.lang.UnsupportedClassVersionError:不支持的major.minor版本51.0

线程“主”中的异常java.lang.UnsupportedClassVersionError,不支持的major.minor版本52.0

java.lang.UnsupportedClassVersionError不支持的major.minor版本51.0

java.lang.UnsupportedOperationException:不支持类加载器-Android multi dex问题

java.lang.UnsupportedOperationException:RecyclerView不支持滚动到绝对位置

java.lang.UnsupportedOperationException:不支持,请使用MenuItemCompat.setOnActionExpandListener()

java.lang.IllegalStateException:软件渲染不支持硬件位图

Spark Scala UDF:java.lang.UnsupportedOperationException:不支持类型为Any的架构

java.lang.RuntimeException:不支持:类 org.spockframework.gentyref.CaptureTypeImpl

java.lang.UnsupportedClassVersionError:module1 / MyNewJava:不支持的major.minor版本51.0

java.lang.RuntimeException:不支持的文字类型类org.apache.spark.sql.Dataset / Spark-JAVA

使用与Eclipse不同的JRE的Ant Javac目标?-“ java.lang.UnsupportedClassVersionError:不支持的major.minor版本51.0”

java.lang.UnsupportedClassVersionError:org / springframework / boot / gradle / plugin / SpringBootPlugin:不支持的major.minor版本52.0

java.lang.UnsupportedClassVersionError:myApp:Linux上不支持的major.minor版本51.0(无法加载类myApp)

Spring Webflux注释的rest控制器不支持ServerHttpRequest作为方法参数:java.lang.NoSuchMethodException

Get播放时发生错误:java.lang.UnsupportedClassVersionError:控制器/路由:不支持major.minor> version