为什么 cipher.getOutputSize() return 值会高于要求?

why would cipher.getOutputSize() return value higher than required?

我正在尝试解密使用 AES256 CBC 加密的文件,这是我的代码:

PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(new CBCBlockCipher(new AESFastEngine()));
cipher.init(false, new ParametersWithIV(new KeyParameter(key), iv));
byte[] outBuf = new byte[cipher.getOutputSize(data.length)];
int processed = cipher.processBytes(data, 0, data.length, outBuf, 0);
processed += cipher.doFinal(outBuf, processed);

这很简单,但是 cipher.getOutputSize(data.length) 总是 return 一个大于需要的值。我总是在缓冲区末尾出现一些奇怪的字符。

我已经尝试解密两个 html 文件,这里是它们的结尾:

</HTML>����������������
// Processed: 9304 Size: 9312

</body></html>��������
// Processed: 636 Buffer size: 640

所以额外的字节大小不一致,我不能只递减'by some'。

我在计算输出数组的大小时做错了什么?

与填充有关。

AES逐块加密,每块长度必须为128位。传入一些不可分割为 128 位块的数据意味着最终的明文块必须 填充 直到它的大小为 128 位。

getOutputSize 返回给您密文的大小您是否应该加密。请记住,明文被填充 然后 加密,因此输入大小与输出大小相同。您可以看到这一点,因为 636 mod 16 = 12636 - 12 + 16 = 640。例如。它四舍五入到最接近的 16 的倍数,因为这是加密前包含的额外填充字节数。

由于您在解密时使用了它,因此数组比所需的要大,因为您正在分配 所需的字节。 getOutputSize 可用于加密和解密,前提是您知道它是用于缓冲区分配的 "worst-case" 方案。

TL;DR: getOutputSize() 让你知道要分配多大的缓冲区(最坏的情况),return 来自 processBytes/doFinal 的值告诉你实际使用了多少缓冲区(确切).

您正在使用 PaddedBufferedBlockCipher 进行解密(以上代码默认为 PKCS7 填充)。 getOutputSize() 在实际看到最终块的解密数据之前无法确定输出明文的确切数量,因此 returned 值将是上限,这就是 return 值在那里的原因processBytes/doFinal 让你知道实际输出了多少。

为简单起见,PaddedBufferedBlockCipher 也忽略了所使用的特定填充方案的细节 - 它仅假设最终块可能包含一些将被删除的填充量。

'outBuf'末尾未使用的字节未被密码写入。特别是,它们将不包含填充。据推测 "weird characters" 是数组初始化的零字节。