如何正确使用bouncycastle的PaddedBufferedBlockCipher?

时间:2013-04-03 02:30:07

标签: java cryptography bouncycastle

我一直在浏览BouncyCastle的加密API的java版本。我对PaddedBufferedBlockCipher课感到有点困惑。我理解(也许是错误的?)它的目的是逐步处理加密,即从文件中读取数据。

当我调用processBytes()一次,提供所有数据一次加密,然后doFinal()它按预期工作。但是,当我多次调用processBytes时,使用适当的偏移量/长度,以便在较小的块中处理,然后是doFinal(),它会失败。任何人都可以解释为什么以下代码失败?值是硬编码的,假设clearText是64字节长,加密是在4 x 16字节块中执行。

byte[] key= Hex.decode("a4ea1a7227e032c37f5635e70ba1bd38a4ea1a7227e032c37f5635e70ba1bd38");
byte[] iv= Hex.decode("a4ea1a7227e032c37f5635e70ba1bd38");
byte[] clearText= Hex.decode("28d3966905e33c063e7b74c7c7dcb2d688d48d53101d2a6901d365146faf0c9cde3da9ef37664a5e32e4e468f9b52f587d76b78caaf9d9823dd9eb2c1d700d7c");

BlockCipher bc  = new AESFastEngine();
CBCBlockCipher cipher   = new CBCBlockCipher(bc);
PaddedBufferedBlockCipher mode  = new PaddedBufferedBlockCipher(cipher);
KeyParameter kp = new KeyParameter(key);
CipherParameters ivAndKey= new ParametersWithIV(kp, iv);
mode.init(true, ivAndKey);

byte[] outBuf   = new byte[mode.getOutputSize(clearText.length)];

int blockSize    = mode.getBlockSize();

// process the 64 bytes of clearText, in 4 x 16-byte chunks 
for (int i = 0; i < 4; i++) {

    mode.processBytes(clearText, i * blockSize, blockSize, outBuf, i * blockSize);
}

try {
    // call doFinal on the last block (bytes 48->64)
    mode.doFinal(outBuf, 48);
} catch (Exception e){}

System.out.println(new String(Hex.encode(outBuf))); 

预期产出为:fe391ed41650f3b344ed3d200ffa3c55e71b1d97dbd91c0fbdd0989c3a48822e7e5230e9d6d073bc0752436d9bea9f26328a11586a290e712fbbf874ddfd4ba14e28600e55c7d6ac69467693320a82d3

但我得到的结果是: 00000000000000000000000000000000fe391ed41650f3b344ed3d200ffa3c55e71b1d97dbd91c0fbdd0989c3a48822e328a11586a290e712fbbf874ddfd4ba14e28600e55c7d6ac69467693320a82d3

修改

根据PeterDettman的建议修改代码:

int bytesProcessed = 0;

for (int i = 0; i < 4; i++) {
            // Fixed to be '+='
    bytesProcessed += mode.processBytes(clearText, i * blockSize, blockSize, outBuf, bytesProcessed);
}

mode.doFinal(outBuf, bytesProcessed);

1 个答案:

答案 0 :(得分:3)

关于如何修复代码:processBytes方法返回它写入输出的实际数量,因此你需要跟踪outBuf中的位置并为每次调用添加返回的长度(同样对于doFinal) 。请注意,您不应在内部假设任何特定的缓冲区大小,或者是否立即或懒惰地刷新“完整”缓冲区。

至于原因:在解密的情况下,填充模式不能输出一个块,直到它知道是否还有更多的块(因为它将从最后一个块中删除填充)。所以它被迫在输出块方面“懒惰”。对于加密,情况并非如此,但我认为,processBytes代码的简单性/一致性也是如此。