我正在使用javax.crypto在java中进行AES CBC解密。我使用以下Cipher类方法:
public final void init (int opmode, Key key, AlgorithmParameters params)
初始化方法,final int update(byte[] input, int inputOffset, int inputLen, byte[] output)
解密数据的方法,final int doFinal(byte[] output, int outputOffset)
方法完成解密。我的查询是这样的:我可以假设doFinal
调用返回给我的数据大小总是小于或等于AES块大小吗?该文档将doFinal方法描述为:
“完成多部分转型 (加密或解密)。流程 任何可能已缓冲的字节 在之前的更新调用中。决赛 转换后的字节存储在 输出缓冲区。“
但它没有说输出缓冲区最多只包含一个数据块。虽然我知道这是AES API的一般行为,这是我的代码到目前为止所表现出的行为,但这种假设是否会持续存在?
答案 0 :(得分:3)
在 general 中(例如,在Cipher
类的上下文中)我不相信这样做是安全的。根据{{1}}方法的javadocs:
如果输出缓冲区太小而无法保存结果,则抛出ShortBufferException。在这种情况下,使用更大的输出缓冲区重复此调用。使用getOutputSize确定输出缓冲区应该有多大。
因此,如果您将输出缓冲区“分配”在调用doFinal方法的位置附近,则调用doFinal
并分配适当大小的缓冲区是有意义的。完成工作。
另一方面,如果你从一个创建的“远离”缓冲区中传入一个缓冲区,那么你可能会遇到更多问题。只要getOutputSize方法返回适当的大小,Cipher实现返回大于块大小的输出就完全合法(至少,根据Java类的公共接口)。
事实上,如果您正在进行CBC解密,那么是否要求您将所有块传递给getOutputSize
方法?在这种情况下,您应该从update
获取完整的纯文本输出,而不仅仅是一个块?
答案 1 :(得分:0)
一般来说,假设缓冲仅适用于一个块是不安全的;当你查看细节时,你可能会发现它取决于填充的类型。使用通常的“PKCS#5”填充,添加至少一个字节且最多 n 字节(对于大小为 n 的块),因此解密系统可能会限制自身到 n 字节的缓冲。一些其他类型的填充稍微复杂一些,例如, CTS需要 2n 个字节的缓冲。 Java加密层现在似乎不支持CTS,但可能会在将来的版本中添加。
在给定Cipher.getOutputSize(len)
个额外输入字节的情况下, len
将为您提供最大输出大小。返回的值可能比实际返回的值稍大,特别是在解密时,因为它取决于在解密时实际找到的填充字节。
可以安全地假设总解密消息长度不超过总加密消息长度(对称加密不涉及数据压缩)。因此,您可以维护两个计数器,一个用于输入数据字节(加密块),另一个用于获取的输出数据字节;差异将是doFinal()
可以获得的最大界限。但无论如何,这就是getOutputSize()
所做的。