Kotlin AES BAD_DECRYPT

问题描述

我正在尝试在 Kotlin 中加密和解密字符串/文件。 我正在使用 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,iv))
        val plainText = cipher.doFinal(cipherText)
        return String(plainText,StandardCharsets.UTF_8)
    }

我哪里做错了?

解决方法

错误在于 encryptFile() 中的 salt 和 IV 是使用 getRandomNonce() 方法确定的,该方法返回一个随机的 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)

通过这些更改,代码在我的机器上成功执行。