Мне нужно зашифровать и отправить данные по TCP (от нескольких 100 байтов до нескольких 100 мегабайт на сообщение) кусками из Java в программу на C ++, и мне нужно отправить размер данных заблаговременно, чтобы получатель знал, когда прекратить чтение текущего сообщения и обработать его, а затем дождаться следующего сообщения (соединение остается открытым, поэтому другого способа указать конец сообщения нет; данные могут быть двоичными, я могу » t использовать флаг для обозначения конца сообщения из-за того, что зашифрованные байты могут случайно оказаться идентичными любому флагу, который я выберу в какой-то момент).
Моя проблема заключается в расчете размера зашифрованного сообщения перед его шифрованием, который в общем случае будет отличаться от длины ввода из-за заполнения и т. Д.
Скажите, что я инициализировал следующим образом:
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) перед циклом. Но как рассчитать размер сообщения? В документации к getOutputSize()
от Cipher говорится, что «этот вызов учитывает любые необработанные (буферизованные) данные из предыдущего вызова обновления и заполнения». Таким образом, это означает, что значение может измениться для одного и того же аргумента функции при нескольких вызовах 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());
??
Если нет, какие у меня есть альтернативы?