写入Room数据库后ByteArray不一致的问题求助
问题分析
你的问题核心出在Room类型转换器使用Json序列化Pair<ByteArray, ByteArray>:kotlinx.serialization的Json默认会将ByteArray编码为Base64字符串,虽然表面上能还原,但Json的序列化规则(如转义、格式处理)会导致二进制数据出现细微偏差。而加密解密对二进制数据的一致性要求极高,一点点偏差都会让解密后的字节流无法被ObjectInputStream正确解析,最终抛出StreamCorruptedException: invalid stream header。
另外,你加密函数中手动用copyOf补全字节到16倍数的操作也存在隐患:填充的0字节会留在解密后的数据流中,可能干扰ObjectInputStream对序列化对象的解析。
解决方案
1. 替换Room类型转换器(核心修复)
放弃Json序列化,改用Base64直接编码二进制数据,避免中间格式转换导致的字节偏差。下面提供两种可行方案:
方案一:分别编码IV和加密数据后拼接
class UserDataConverters { private val base64 = Base64.DEFAULT @TypeConverter fun fromTokenPair(pair: Pair<ByteArray, ByteArray>): String { val ivStr = String(base64.encode(pair.first)) val dataStr = String(base64.encode(pair.second)) // 用Base64中不会出现的分隔符拼接 return "$ivStr|||$dataStr" } @TypeConverter fun toTokenPair(serializedPair: String): Pair<ByteArray, ByteArray> { val parts = serializedPair.split("|||") val ivBytes = base64.decode(parts[0].toByteArray()) val dataBytes = base64.decode(parts[1].toByteArray()) return Pair(ivBytes, dataBytes) } }
方案二:将整个Pair序列化为ByteArray后再编码
利用你已有的ByteArray工具函数,直接序列化Pair对象:
class UserDataConverters { private val base64 = Base64.DEFAULT @TypeConverter fun fromTokenPair(pair: Pair<ByteArray, ByteArray>): String { val pairBytes = pair.toByteArray() return String(base64.encode(pairBytes)) } @TypeConverter fun toTokenPair(serializedPair: String): Pair<ByteArray, ByteArray> { val pairBytes = base64.decode(serializedPair.toByteArray()) return fromByteArray(pairBytes) } }
2. 修正加密函数的填充逻辑
去掉手动补全字节的代码,让Cipher自动处理填充(AES默认使用PKCS5Padding,与PKCS7兼容,能正确处理非16倍数的数据流):
override fun <T : Serializable> encryptData(data: T): Pair<ByteArray, ByteArray> { val temp = data.toByteArray() // 移除手动补全代码,Cipher自动处理填充 cipher.init(Cipher.ENCRYPT_MODE, getKey()) val ivBytes = cipher.iv val encryptedArray = cipher.doFinal(temp) return Pair(ivBytes, encryptedArray) }
验证效果
替换类型转换器并修正加密函数后,写入数据库再读取解密的流程即可正常执行,不会再出现流头错误。
内容的提问来源于stack exchange,提问作者Harnick
相关产品推荐
相关产品推荐

