AES带初始化向量加密数据存SQL库后解密报Invalid IV错误求助
问题原因
- IV存储内容错误:你存入数据库的
[B@5a36422是Kotlin/Java中ByteArray调用默认toString()方法的输出,仅为该字节数组对象的内存地址标识,完全不是IV的实际字节内容,解密时传入的是无效IV值,因此触发报错。 - 加密数据转换错误:AES加密后的结果是二进制字节数组,包含大量不符合UTF-8编码规范的字节,直接用
toString(Charsets.UTF_8)转换会发生数据丢失、字符转义,解密时转换回的字节数组和原始加密数据不一致。 - 密钥生成逻辑错误:你当前
getKey()方法每次调用都会执行genKey()生成新密钥,覆盖之前的旧密钥,加密和解密使用的密钥不匹配,就算IV正确也无法解密成功。
修复方案
1. 修复密钥生成逻辑
仅当AndroidKeyStore中不存在对应别名的密钥时才生成新密钥,修改Encrypted类的getKey方法:
fun getKey(): SecretKey { val keystore = KeyStore.getInstance("AndroidKeyStore") keystore.load(null) // 先判断密钥是否已存在,不存在再生成 if (!keystore.containsAlias("MyKeyAlias")) { keyGenerator.init(keyGenParameterSpec) keyGenerator.generateKey() } val secretKeyEntry = keystore.getEntry("MyKeyAlias", null) as KeyStore.SecretKeyEntry return secretKeyEntry.secretKey } // 同时删除原来getKey方法里调用genKey()的逻辑,genKey()方法可以直接删掉
2. 二进制数据转Base64存储
所有二进制数据(IV、加密结果)不要直接转UTF-8字符串,改为转Base64编码的可打印字符串再存入数据库,修改Encrypted类的加密输出逻辑:
import android.util.Base64 // 加密后输出的部分修改为: val pair = encryptData(wordE) // 加密结果转Base64 val encrypted = Base64.encodeToString(pair.second, Base64.DEFAULT) // IV转Base64 val iv = Base64.encodeToString(pair.first, Base64.DEFAULT)
3. 修复解密逻辑
解密时先把Base64格式的字符串转回原始字节数组,再进行解密操作,修改Decrypted类代码:
import android.util.Base64 fun decryptData(data: String, iv : String) : String { // 先把Base64字符串转回原始字节数组 val ivBytes = Base64.decode(iv, Base64.DEFAULT) val encryptedBytes = Base64.decode(data, Base64.DEFAULT) val spec = IvParameterSpec(ivBytes) val decipher = Cipher.getInstance("AES/CBC/NoPadding") decipher.init(Cipher.DECRYPT_MODE, getKey(), spec) return decipher.doFinal(encryptedBytes).toString(Charsets.UTF_8).trim() }
内容的提问来源于stack exchange,提问作者Santi
相关产品推荐
相关产品推荐

