Мне нужно зашифровать и отправить данные через TCP (от нескольких 100 байт до нескольких 100 мегабайт на сообщение) в кусках от Java до C++-программы и необходимо заранее отправить размер данных, чтобы получатель знает, когда прекратить чтение текущего сообщения и обработать его, а затем ждать следующего сообщения (соединение остается открытым, поэтому нет другого способа указать конец сообщения, так как данные могут быть двоичными, я не могу использовать флаг для указать конец сообщения из-за возможности того, что зашифрованные байты могут случайно оказаться идентичными любому выбранному флагу в какой-либо точке).getOutputSize постоянство?
Моя проблема вычисления зашифрованного размер сообщения перед шифрованием, которое будет в общем случае отличается от длины входа в связи с прокладкой т.д.
Скажем, я инициализируется следующим образом:
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's 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());
??
Если нет, то какие у меня альтернативы?
Ваше угадывание, исправление, молитва. Используйте SSL/TLS. Java JSSE имеет простую в использовании поддержку SSL. –
Грег, я не могу этого сделать, потому что система должна быть симметричной, только с закрытым ключом - аутентификация с открытым ключом/обмен ключами. Текущая реализация Java не поддерживает это. – Prune