科特林 AES BAD_DECRYPT
Kotlin AES BAD_DECRYPT
我正在尝试在 Kotlin 中加密和解密 strings/files。
我正在使用 Java https://mkyong.com/java/java-aes-encryption-and-decryption/ 中的以下教程来实现这一点。
当我尝试 运行 它时,它会抛出“... Cipher functions:OPENSSL_internal:BAD_DECRYPT ...”的错误,在 Decrypt 函数中执行 doFinal 时出错。
我花了好几个小时试图解决这个问题,但没有成功。
这是代码。
private const val ENCRYPT_ALGO = "AES/GCM/NoPadding"
private const val TAG_LENGTH_BIT = 128
private const val IV_LENGTH_BYTE = 12
private const val SALT_LENGTH_BYTE = 16
fun getRandomNonce(): ByteArray {
val nonce = ByteArray(16)
SecureRandom().nextBytes(nonce)
return nonce
}
fun getAESKeyFromPassword(password: CharArray?, salt: ByteArray?): SecretKey {
val factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256")
val spec: KeySpec = PBEKeySpec(password, salt, 65536, 256)
return SecretKeySpec(factory.generateSecret(spec).encoded, "AES")
}
fun encryptFile(pText: ByteArray, password: String): String {
val salt: ByteArray = getRandomNonce()
val iv: ByteArray = getRandomNonce()
val aesKeyFromPassword: SecretKey = getAESKeyFromPassword(password.toCharArray(), salt)
val cipher = Cipher.getInstance(ENCRYPT_ALGO)
cipher.init(Cipher.ENCRYPT_MODE, aesKeyFromPassword, GCMParameterSpec(TAG_LENGTH_BIT, iv))
val cipherText = cipher.doFinal(pText)
val cipherTextWithIvSalt: ByteArray =
ByteBuffer.allocate(iv.size + salt.size + cipherText.size)
.put(iv)
.put(salt)
.put(cipherText)
.array()
return Base64.getEncoder().encodeToString(cipherTextWithIvSalt)
}
fun decryptFile(cText: String, password: String): String {
val decode: ByteArray = Base64.getDecoder().decode(cText.toByteArray())
val bb: ByteBuffer = ByteBuffer.wrap(decode)
val iv = ByteArray(IV_LENGTH_BYTE)
bb.get(iv)
val salt = ByteArray(SALT_LENGTH_BYTE)
bb.get(salt)
val cipherText = ByteArray(bb.remaining())
bb.get(cipherText)
val aesKeyFromPassword: SecretKey = getAESKeyFromPassword(password.toCharArray(), salt)
val cipher = Cipher.getInstance(ENCRYPT_ALGO)
cipher.init(Cipher.DECRYPT_MODE, aesKeyFromPassword, GCMParameterSpec(TAG_LENGTH_BIT, iv))
val plainText = cipher.doFinal(cipherText)
return String(plainText, StandardCharsets.UTF_8)
}
我哪里错了?
错误在于 encryptFile()
盐和 IV 是使用 getRandomNonce()
方法确定的,returns 一个随机的 16 字节数组。但在 decryptFile()
中,假定 IV 的长度为 IV_LENGTH_BYTE
(12 字节),盐的长度为 SALT_LENGTH_BYTE
(16 字节)。 IE。两种实现在 IV 长度方面都不一致。请注意,对于 GCM,IV 的长度确实必须为 12 个字节。
一个可能的修复方法是修改 getRandomNonce()
方法如下:
fun getRandomNonce(size: Int): ByteArray {
val nonce = ByteArray(size)
SecureRandom().nextBytes(nonce)
return nonce
}
以及 encryptFile()
中的以下更改:
val salt: ByteArray = getRandomNonce(SALT_LENGTH_BYTE)
val iv: ByteArray = getRandomNonce(IV_LENGTH_BYTE)
经过这些更改,代码已在我的机器上成功执行。
我正在尝试在 Kotlin 中加密和解密 strings/files。 我正在使用 Java https://mkyong.com/java/java-aes-encryption-and-decryption/ 中的以下教程来实现这一点。
当我尝试 运行 它时,它会抛出“... Cipher functions:OPENSSL_internal:BAD_DECRYPT ...”的错误,在 Decrypt 函数中执行 doFinal 时出错。
我花了好几个小时试图解决这个问题,但没有成功。
这是代码。
private const val ENCRYPT_ALGO = "AES/GCM/NoPadding"
private const val TAG_LENGTH_BIT = 128
private const val IV_LENGTH_BYTE = 12
private const val SALT_LENGTH_BYTE = 16
fun getRandomNonce(): ByteArray {
val nonce = ByteArray(16)
SecureRandom().nextBytes(nonce)
return nonce
}
fun getAESKeyFromPassword(password: CharArray?, salt: ByteArray?): SecretKey {
val factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256")
val spec: KeySpec = PBEKeySpec(password, salt, 65536, 256)
return SecretKeySpec(factory.generateSecret(spec).encoded, "AES")
}
fun encryptFile(pText: ByteArray, password: String): String {
val salt: ByteArray = getRandomNonce()
val iv: ByteArray = getRandomNonce()
val aesKeyFromPassword: SecretKey = getAESKeyFromPassword(password.toCharArray(), salt)
val cipher = Cipher.getInstance(ENCRYPT_ALGO)
cipher.init(Cipher.ENCRYPT_MODE, aesKeyFromPassword, GCMParameterSpec(TAG_LENGTH_BIT, iv))
val cipherText = cipher.doFinal(pText)
val cipherTextWithIvSalt: ByteArray =
ByteBuffer.allocate(iv.size + salt.size + cipherText.size)
.put(iv)
.put(salt)
.put(cipherText)
.array()
return Base64.getEncoder().encodeToString(cipherTextWithIvSalt)
}
fun decryptFile(cText: String, password: String): String {
val decode: ByteArray = Base64.getDecoder().decode(cText.toByteArray())
val bb: ByteBuffer = ByteBuffer.wrap(decode)
val iv = ByteArray(IV_LENGTH_BYTE)
bb.get(iv)
val salt = ByteArray(SALT_LENGTH_BYTE)
bb.get(salt)
val cipherText = ByteArray(bb.remaining())
bb.get(cipherText)
val aesKeyFromPassword: SecretKey = getAESKeyFromPassword(password.toCharArray(), salt)
val cipher = Cipher.getInstance(ENCRYPT_ALGO)
cipher.init(Cipher.DECRYPT_MODE, aesKeyFromPassword, GCMParameterSpec(TAG_LENGTH_BIT, iv))
val plainText = cipher.doFinal(cipherText)
return String(plainText, StandardCharsets.UTF_8)
}
我哪里错了?
错误在于 encryptFile()
盐和 IV 是使用 getRandomNonce()
方法确定的,returns 一个随机的 16 字节数组。但在 decryptFile()
中,假定 IV 的长度为 IV_LENGTH_BYTE
(12 字节),盐的长度为 SALT_LENGTH_BYTE
(16 字节)。 IE。两种实现在 IV 长度方面都不一致。请注意,对于 GCM,IV 的长度确实必须为 12 个字节。
一个可能的修复方法是修改 getRandomNonce()
方法如下:
fun getRandomNonce(size: Int): ByteArray {
val nonce = ByteArray(size)
SecureRandom().nextBytes(nonce)
return nonce
}
以及 encryptFile()
中的以下更改:
val salt: ByteArray = getRandomNonce(SALT_LENGTH_BYTE)
val iv: ByteArray = getRandomNonce(IV_LENGTH_BYTE)
经过这些更改,代码已在我的机器上成功执行。