如何确认RSA解密AES参数及消息长度的正确性?添加校验值是否安全?
问题解答
核心结论
添加4字节常量校验是安全的,不会给应用带来额外安全风险,反而能有效避免因解密乱码导致的内存溢出问题。
具体分析
当前方案的隐患
你使用的RSA默认是PKCS#1 v1.5填充,这种填充方式的解密逻辑在遇到非法密文时,不会抛出异常,而是返回一段随机的明文数据。这就导致你解析出的messageLength可能是一个超大的随机整数,创建对应长度的ByteArray时直接触发内存溢出。4字节校验的合理性
在加密阶段,将一个固定的4字节常量(比如0xDEADBEEF,按小端序转成字节数组)和AES参数、消息长度拼接后再用RSA加密;解密后先提取并校验这个常量:- 如果校验不匹配,直接终止流程,避免后续创建超大数组。
- 这个常量是公开的冗余数据,不会泄露任何密钥或敏感信息。攻击者伪造的密文解密后恰好匹配该常量的概率极低(仅1/2^32),几乎不可能绕过校验。
更优的替代方案
相比手动加校验,更推荐改用RSA OAEP填充,它在解密非法密文时会主动抛出BadPaddingException,从根源上避免乱码解密的问题。修改代码如下:// 改用OAEP填充的RSA实例 val rsaCipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding") rsaCipher.init(Cipher.DECRYPT_MODE, privateKey) try { val rsaDecoded = rsaCipher.doFinal(encryptedAesParametersAndMessageLength) // 后续解析逻辑... } catch (e: BadPaddingException) { // 密文非法或不是用对应公钥加密的,直接终止 throw IllegalArgumentException("Invalid encrypted parameters", e) }额外防护建议
即使加了校验或改用OAEP,仍建议对解析出的length做范围限制,比如限制最大长度为100MB(根据你的业务场景调整),避免合法密文中的异常长度值导致内存问题:val maxAllowedLength = 100 * 1024 * 1024 // 100MB if (length <= 0 || length > maxAllowedLength) { throw IllegalArgumentException("Invalid message length") } val encryptedMessage = ByteArray(length)
修正后的带校验代码示例
// 加密端:拼接校验值、AES参数、消息长度 val CHECK_VALUE = ByteBuffer.allocate(4).order(ByteOrder.LITTLE_ENDIAN).putInt(0xDEADBEEF).array() val dataToEncrypt = ByteBuffer.allocate(CHECK_VALUE.size + 48 + 4) .put(CHECK_VALUE) .put(aesParameters) .put(messageLength) .array() // 用RSA公钥加密dataToEncrypt... // 解密端 val rsaCipher = Cipher.getInstance("RSA") rsaCipher.init(Cipher.DECRYPT_MODE, privateKey) val rsaDecoded = rsaCipher.doFinal(encryptedAesParametersAndMessageLength) // 提取并校验固定值 val checkValueBytes = ByteArray(4) val aesParameters = ByteArray(48) val messageLength = ByteArray(4) System.arraycopy(rsaDecoded, 0, checkValueBytes, 0, 4) System.arraycopy(rsaDecoded, 4, aesParameters, 0, 48) System.arraycopy(rsaDecoded, 4 + 48, messageLength, 0, 4) val decodedCheckValue = ByteBuffer.wrap(checkValueBytes).order(ByteOrder.LITTLE_ENDIAN).int if (decodedCheckValue != 0xDEADBEEF) { throw IllegalArgumentException("Invalid encrypted parameters: check value mismatch") } // 长度校验 val maxAllowedLength = 100 * 1024 * 1024 val length = ByteBuffer.wrap(messageLength).order(ByteOrder.LITTLE_ENDIAN).int if (length <= 0 || length > maxAllowedLength) { throw IllegalArgumentException("Invalid message length") } val aesEncryptor = AesEncryptor(aesParameters) val encryptedMessage = ByteArray(length)
内容的提问来源于stack exchange,提问作者HellOfSpades
相关产品推荐
相关产品推荐

