getOutputSize постоянство? - PullRequest
       16

getOutputSize постоянство?

3 голосов
/ 03 марта 2010

Мне нужно зашифровать и отправить данные по 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());

??

Если нет, какие у меня есть альтернативы?

1 Ответ

1 голос
/ 03 марта 2010

При использовании заполнения PKCS5 размер сообщения после заполнения будет:

padded_size = original_size + BLOCKSIZE - (original_size % BLOCKSIZE);

Выше приведен полный размер всего сообщения (до вызова doFinal()) с учетом полного размера входного сообщения. Мне приходит в голову, что вы на самом деле хотите знать только длину последней части - все, что вам нужно сделать, это сохранить выходной байтовый массив вызова doFinal() и использовать метод .length() в этом массиве.

...