InvalidAlgorithmParameterException: неподдерживаемая длина IV: 16 байт. Поддерживается только IV длиной 12 байт.Android

Форум для тех, кто программирует под Android
Ответить
Anonymous
 InvalidAlgorithmParameterException: неподдерживаемая длина IV: 16 байт. Поддерживается только IV длиной 12 байт.

Сообщение Anonymous »

Я пытаюсь реализовать шифрование и дешифрование данных с помощью Cipher. Это мой код:

Код: Выделить всё

class CryptographyManagerImpl : CryptographyManager {
private val KEY_SIZE_BITS: Int = 256
private val GCM_TAG_BITS: Int = 128
private val ANDROID_KEYSTORE = "AndroidKeyStore"

private val KEY_NAME = "MySecretKey"
private val ENCRYPTION_BLOCK_MODE = KeyProperties.BLOCK_MODE_GCM
private val ENCRYPTION_PADDING = KeyProperties.ENCRYPTION_PADDING_NONE
private val ENCRYPTION_ALGORITHM = KeyProperties.KEY_ALGORITHM_AES

@Throws(BiometricEncryptionException::class)
override fun getInitializedCypherForEncryption(): Cipher {
try {
val cipher = getCipher()
val secretKey = getOrCreateSecretKey(KEY_NAME)
cipher.init(Cipher.ENCRYPT_MODE, secretKey)
return cipher
} catch (e: Exception) {
throw BiometricEncryptionException()
}
}

@Throws(BiometricEncryptionException::class)
@OptIn(ExperimentalEncodingApi::class)
override fun getInitializedCypherForDecryption(
encryptedData: String
): Cipher {
try {
val cipher = getCipher()
val secretKey = getOrCreateSecretKey(KEY_NAME)
val parts = encryptedData.split(":")
val iv = Base64.decode(parts[1], android.util.Base64.DEFAULT)
cipher.init(
Cipher.DECRYPT_MODE,
secretKey,
GCMParameterSpec(GCM_TAG_BITS, iv)
)
return cipher
} catch (e: Exception) {
throw BiometricEncryptionException()
}
}

@Throws(BiometricEncryptionException::class)
@OptIn(ExperimentalEncodingApi::class)
override fun encryptData(
data: String,
cipher: Cipher
): String {
try {
val byteArray = data.toByteArray(StandardCharsets.UTF_8)
val encryptedText = cipher.doFinal(byteArray)
val base64Text = Base64.encode(encryptedText, android.util.Base64.DEFAULT) + ":" + Base64.encode(cipher.iv, android.util.Base64.DEFAULT)
return base64Text
} catch (e: Exception) {
throw BiometricEncryptionException()
}
}

@Throws(BiometricEncryptionException::class)
@OptIn(ExperimentalEncodingApi::class)
override fun decryptData(
encryptedData: String,
cipher: Cipher
): String {
try {
val parts = encryptedData.split(":")
val encryptedText = Base64.decode(parts[0], android.util.Base64.DEFAULT)
val byteArray = cipher.doFinal(encryptedText)
val data = String(byteArray, StandardCharsets.UTF_8)
return data
} catch (e: Exception) {
throw BiometricEncryptionException()
}
}

private fun getCipher(): Cipher {
val transformation = "$ENCRYPTION_ALGORITHM/$ENCRYPTION_BLOCK_MODE/$ENCRYPTION_PADDING"
return Cipher.getInstance(transformation)
}

private fun getOrCreateSecretKey(keyName: String): SecretKey {
val keyStore = KeyStore.getInstance(ANDROID_KEYSTORE).apply {
load(null)
}
keyStore.getKey(keyName, null)?.let {
return it as SecretKey
}

val paramsBuilder = KeyGenParameterSpec.Builder(
keyName,
KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT
).apply {
setBlockModes(ENCRYPTION_BLOCK_MODE)
setEncryptionPaddings(ENCRYPTION_PADDING)
setKeySize(KEY_SIZE_BITS)
setUserAuthenticationRequired(true)
setInvalidatedByBiometricEnrollment(true)
}

val keyGenParams = paramsBuilder.build()
val keyGenerator = KeyGenerator.getInstance(
ENCRYPTION_ALGORITHM,
ANDROID_KEYSTORE
)
keyGenerator.init(keyGenParams)
return keyGenerator.generateKey()
}
}
Приведенный выше код работает безупречно на Android 16. Однако на Android 10 я получаю исключение, показанное в заголовке этого вопроса, при попытке вызвать cipher.init для шифра дешифрования.
Некоторые вещи, которые я заметил:
  • При вызове getInitializedCypherForEncryption , если я проверю cipher.iv сразу после cipher.init, я всегда получаю 12-байтовый массив;
  • Поскольку я использую BiometricPrompt и CryptoObject для дополнительной безопасности, если я снова проверю cipher.iv сразу после захвата проверенного зашифрованного объекта, IV изменится на 16-байтовый массив с другими значениями;
  • Теперь getInitializedCypherForDecryption выдает вышеупомянутое исключение прямо в cipher.init, поскольку IV изменился сам по себе;
  • Я попытался сохранить исходный 12-байтовый IV, чтобы повторно использовать его впоследствии, но полученные данные расшифровываются неправильно;
  • Я также попытался сохранить исходный зашифрованный объект вместо передачи проверенного через CryptoObject, но я, очевидно, получаю исключение android.security.KeyStoreException: ключевой пользователь не аутентифицирован;
  • Я также попытался сгенерировать свой собственный 12-байтовый IV и установил в getInitializedCypherForEncryption cipher.init. Та же проблема сохраняется, а также нарушает код для Android 16, поскольку установка IV вручную приводит к исключению.
Я что-то упустил? Заранее спасибо.

Подробнее здесь: https://stackoverflow.com/questions/798 ... nly-12-byt
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «Android»