我需要通过TCP加密和发送数据(从每个消息的几个100字节到几百兆字节) in chunks 从Java到C ++程序,并且需要发送大小的提前数据,以便收件人知道何时停止读取当前消息并处理它,然后等待下一条消息(连接保持打开状态,因此没有其他方式指示消息结束;因为数据可以是二进制的,我可以由于加密字节可能随机碰巧与我在某一点选择的任何标志相同,因此使用标志来指示消息结束。
我的问题是在加密之前计算加密的邮件大小,由于填充等原因通常会与输入长度不同。
说我已经初始化如下:
AlgorithmParameterSpec paramSpec = new IvParameterSpec(initv);
encipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
mac = Mac.getInstance("HmacSHA512");
encipher.init(Cipher.ENCRYPT_MODE, key, paramSpec);
mac.init(key);
buf = new byte[encipher.getOutputSize(blockSize)];
然后我这样发送数据(并且还有一个类似的函数,使用输入流而不是byte[]
):
public void writeBytes(DataOutputStream out, byte[] input) {
try {
//mac.reset(); // Needed ?
int left = input.length;
int offset = 0;
while (left > 0)
{
int chunk = Math.min(left, blockSize);
int ctLength = encipher.update(input, offset, chunk, buf, 0);
mac.update(input, offset, chunk);
out.write(buf, 0, ctLength);
left -= chunk;
offset += chunk;
}
out.write(encipher.doFinal(mac.doFinal());
out.flush();
} catch (Exception e) {
e.printStackTrace();
}
}
但是如何预先计算将发送到接收计算机的输出大小?
基本上,我想在循环之前输出out.writeInt(messageSize)。但是如何计算messageSize? Cipher getOutputSize()
的文档说“此调用会考虑先前更新调用和填充中的任何未处理(缓冲)数据。”所以这似乎意味着,对于update()
或doFinal()
的多次调用,相同函数参数的值可能会发生变化...如果blockSize
是AES CBC的倍数,我可以假设块大小以避免填充,我应该为每个块有一个常量值?也就是说,只需检查_blockSize % encipher.getOutputSize(1) != 0
然后再写入写入功能
int messageSize = (input.length / blockSize) * encipher.getOutputSize(blockSize) +
encipher.getOutputSize(input.length % blockSize + mac.getMacLength());
...
如果没有,我有哪些替代方案?
答案 0 :(得分:1)
使用PKCS5填充时,填充后的消息大小为:
padded_size = original_size + BLOCKSIZE - (original_size % BLOCKSIZE);
在给定输入消息的完整大小的情况下,上面给出了整个消息的完整大小(直到doFinal()
调用)。在我看来,你实际上只想知道最终部分的长度 - 你需要做的就是存储doFinal()
调用的输出字节数组,并在该数组上使用.length()
方法