【问题标题】:Cipher.doFinal output sizeCipher.doFinal 输出大小
【发布时间】:2010-08-13 09:56:09
【问题描述】:

我正在使用 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 的一般行为,这是我的代码到目前为止所表现出的行为,但是这个假设会一直成立吗?

【问题讨论】:

  • 为了清楚起见,我需要多次调用更新函数,因为我正在获取块中的加密数据。我没有完整的加密数据,所以我无法一次调用 doFinal 来一步获取输出。

标签: java aes finalize encryption


【解决方案1】:

一般中(如在Cipher 类的上下文中)我认为假设这一点是不安全的。根据javadocsdoFinal 方法:

如果输出缓冲区太小而无法容纳结果,则会抛出 ShortBufferException。在这种情况下,使用更大的输出缓冲区重复此调用。使用getOutputSize 确定输出缓冲区的大小。

因此,如果您在调用 doFinal 方法的“附近”分配输出缓冲区,那么调用 getOutputSize 并分配适当大小的缓冲区是有意义的。任务完成。

另一方面,如果您从“远处”传入一个缓冲区,该缓冲区被创建为正好是块大小,您可能会遇到更多麻烦。只要 getOutputSize 方法返回适当的大小,Cipher 实现返回大于块大小的输出是完全合法的(至少,根据 Java 类的公共接口)。

事实上,如果您在进行 CBC 解密,那不是需要您将 所有 块传递给 update 方法吗?在这种情况下,您应该从doFinal 获取完整的明文输出,而不是单个块?

【讨论】:

  • update和'doFinal`都使用getOutputSize(fixed input size)的字节数组是否安全?
  • @Jin 我不知道这是否真的有意义,因为它们是两个不同的东西。提供给update 的字节数组应该是您用来更新密码的数据的大小——它需要与输入 中的字节数相同。如果这绝对小于或等于getOutputSize(),那么您可以重用相同的数组。但在实践中,我怀疑这会比有用更令人困惑。
【解决方案2】:

一般来说,假设缓冲只针对一个块是不安全的;当您查看细节时,您可能会发现它取决于填充的类型。使用通常的“PKCS#5”填充,添加至少一个字节,最多 n 个字节(对于大小为 n 的块),因此解密系统可能会限制自己n 个字节的缓冲。其他一些类型的填充有点复杂,例如CTS 需要 2n 字节的缓冲。 Java 加密层目前似乎不支持 CTS,但可能会在未来的版本中添加。

Cipher.getOutputSize(len) 会给你最大的输出大小,给定len 额外的输入字节。返回的值可能会比实际返回的值大一些,尤其是在解密时,因为它取决于解密时实际找到的填充字节。

可以安全地假设总解密消息长度不超过总加密消息长度(对称加密不涉及数据压缩)。所以你可以维护两个计数器,一个用于输入数据字节(加密块),一个用于获得的输出数据字节;差异将是可以从doFinal() 获得的最大界限。但这就是getOutputSize() 所做的。

【讨论】:

  • 在我的例子中使用的填充只是'PKCS5Padding'。这是否意味着我可以假设最大输出大小为 AES 块大小?我不能使用'Cipher.getOutputSize(len)'的原因是因为存储'doFinal()'输出的缓冲区已分配并从很远的代码传递给我的模块,我不应该修改。该分配缓冲区的大小是 AES 块大小。
  • 你不能假设,但你可以检查一下。如果块的大小为 n,并且加密消息包含 k 个块,则解密消息的总长度在 n(k-1) 之间和(nk)-1(含)。使用计数器,您可以(在运行时)知道剩余的缓冲数据在解密时是否适合大小为 n 的缓冲区。您不能提前假设,因为这不是 Java Cryptographic Architecture 的保证属性。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-07-02
  • 2013-03-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-04-11
相关资源
最近更新 更多