BiometricPrompt: как зашифровать несколько строк? - PullRequest
4 голосов
/ 03 мая 2019

Мне нужно зашифровать несколько строк с использованием биометрической аутентификации в моем приложении.Я использую этот код:

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?Я только что получил IV от BiometricPrompt.

1 Ответ

1 голос
/ 03 мая 2019

Вы можете добавить параметр IvParameterSpec к cipher.init. Конечно, это, вероятно, означает, что вам нужно провести рефакторинг getEncryptCipher и затем вызвать cipher.init


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

Вы пытаетесь сделать слишком много в этой строке; Его трудно прочитать, и это не повлияет на производительность, если вы введете одну или две переменные.

...