8

我需要在我的应用程序中使用生物特征认证来加密几个字符串。我正在使用这段代码:

val promptInfo = BiometricPrompt.PromptInfo.Builder()
        .setTitle("Title")
        .setSubtitle("subtitle")
        .setDescription("description")
        .setNegativeButtonText("button")
        .build()
val cryptoObject = BiometricPrompt.CryptoObject(getEncryptCipher())
val biometricPrompt = BiometricPrompt(requireActivity(), Executors.newSingleThreadExecutor(), object : BiometricPrompt.AuthenticationCallback() {
    override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult) {
        val encodedString1 = Base64.encodeToString(result.cryptoObject?.cipher!!.doFinal(string1), Base64.DEFAULT)
        val encodedString2 = Base64.encodeToString(result.cryptoObject?.cipher!!.doFinal(string2), Base64.DEFAULT) // <- I got a crash in this line
        save(encodedString1, encodedString2)
    }
})
biometricPrompt.authenticate(promptInfo, cryptoObject)


fun getEncryptCipher(): Cipher {
    var keyStore: KeyStore = KeyStore.getInstance("AndroidKeyStore")
    keyStore.load(null)
    if (!isKeyExists()) {
        createKey()
    }
    val key = keyStore.getKey("MyKeyAlias", null)
    val cipher = Cipher.getInstance("${KeyProperties.KEY_ALGORITHM_AES}/${KeyProperties.BLOCK_MODE_CBC}/${KeyProperties.ENCRYPTION_PADDING_PKCS7}")
    cipher.init(Cipher.ENCRYPT_MODE, key)
    return cipher
}

fun createKey() {
    val keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, PROVIDER_ANDROID_KEYSTORE)
    val builder = KeyGenParameterSpec.Builder("MyKeyAlias", KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT)
            .setBlockModes(KeyProperties.BLOCK_MODE_CBC)
            .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7)
            .setUserAuthenticationRequired(true)
    keyGenerator.init(builder.build())
    keyGenerator.generateKey()
}

第一个字符串编码良好。但是当我尝试编码第二个字符串时,我遇到了崩溃:

java.lang.IllegalStateException: IV has already been used. Reusing IV in encryption mode violates security best practices.
    at android.security.keystore.AndroidKeyStoreUnauthenticatedAESCipherSpi.addAlgorithmSpecificParametersToBegin(AndroidKeyStoreUnauthenticatedAESCipherSpi.java:244)
    at android.security.keystore.AndroidKeyStoreCipherSpiBase.ensureKeystoreOperationInitialized(AndroidKeyStoreCipherSpiBase.java:237)
    at android.security.keystore.AndroidKeyStoreCipherSpiBase.engineDoFinal(AndroidKeyStoreCipherSpiBase.java:495)
    at javax.crypto.Cipher.doFinal(Cipher.java:2055)
    at com.me.myapp.MyFragment$MyMethod$biometricPrompt$1.onAuthenticationSucceeded(MyFragment.kt:49)
    at androidx.biometric.BiometricFragment$2$2.run(BiometricFragment.java:109)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
    at java.lang.Thread.run(Thread.java:764)

据我所知,我应该为每个字符串使用不同的 IV。但是如何设置新的IV?我刚收到来自 BiometricPrompt 的 IV。

4

1 回答 1

0

您可以将IvParameterSpec参数添加到cipher.init. 当然,这可能意味着您必须重构并在之后getEncryptCipher调用cipher.init


val encodedString2 = Base64.encodeToString(result.cryptoObject?.cipher!!.doFinal(string2), Base64.DEFAULT) // <- I got a crash in this line

你在这条线上做的太多了;它既难以阅读,而且如果您引入一个或两个变量,它不会对性能产生任何影响。

于 2019-05-03T19:26:05.373 回答