Хобрук: Ваш путь к мастерству в программировании

Проблемы с чтением и расшифровкой очень БОЛЬШИХ файлов в байтах на Java

При чтении из очень большого зашифрованного файла на Java я использую следующий код:

FileInputStream in = new FileInputStream("file.txt");
ByteArrayOutputStream baos = new ByteArrayOutputStream();

Writer writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(saveLocation), "utf-8"));

int read;
byte buffer[] = new byte[16384];
byte getData[] = new byte[16384];

while((read = in.read(buffer)) != -1)
{

 baos.write(buffer, 0, read);

 Cipher cipher = Cipher.getInstance(symCipher);
 IvParameterSpec ivParameterSpec = new IvParameterSpec(initVecBytes);
 cipher.init(Cipher.DECRYPT_MODE, originalKey, ivParameterSpec);
 byte[] original = cipher.doFinal(baos.toByteArray());
 String s = new String(original);
 writer.append(s);
 baos.reset();
}

writer.close();

Поскольку файл очень большой (слишком большой для меня, чтобы загрузить его в память за один раз), я читаю его в небольшой буфер, затем шифрую небольшие байты данных и, наконец, записываю их в файл.

Однако, когда я это делаю, некоторые данные выглядят поврежденными:

</AddressLine><_��SR����_�hEE</AddressLine></AddressLines><Postcode>

Когда я использую файл меньшего размера, размер которого не 16 КБ, он работает нормально, кажется, я получаю только небольшое количество поврежденных данных в начале чтения нового массива, затем снова все в порядке, пока не будет прочитан следующий массив , и так далее.

У кого-нибудь есть идеи, почему это не работает должным образом?

16.05.2016

  • Что такое symCipher? 16.05.2016
  • Почему бы вам не использовать потоки, предназначенные для такого рода вещей? На ум приходят CipherInputStream и CipherOutputStream. Вы также можете использовать метод Cipher#update(byte). 16.05.2016
  • Вам нужно .init один раз, затем запустить каждый буфер, кроме необязательно последнего, до .update, затем последний (или пустой) до .doFinal, все, как описано в javadoc для Cipher. Кроме того: запись в BAOS, а затем обратное чтение - пустая трата времени, и .update, и .doFinal могут принимать диапазон массива; и декодирование байтов по умолчанию в String, а затем переход к Writer, который кодирует обратно в байты, всегда является дорогостоящим и работает только в том случае, если кодировка по умолчанию представляет собой полный однобайтовый код, что не всегда так; вместо этого просто напишите байты в OutputStream. ... 16.05.2016
  • ... Или, как предлагает @Artjom, пусть Cipher*Stream сделает это за вас. 16.05.2016

Ответы:


1

Это не работает, потому что большинство шифров имеют состояние. В частности, в режиме цепочки зашифрованных блоков открытый текст должен подвергаться операции XOR с предыдущим блоком зашифрованного текста. Но каждые 16k вместо этого вы выполняете операцию XOR с IV. Вы не можете повторно инициализировать Cipher в середине операции расшифровки.

Вот пять строк кода, на которые ссылается EJP.

Cipher cipher = Cipher.getInstance(symCipher);
cipher.init(Cipher.DECRYPT_MODE, originalKey, new IvParameterSpec(initVecBytes));
try (InputStream in = Files.newInputStream(Paths.get("file.txt"))) {
  Files.copy(new CipherInputStream(in, cipher), Paths.get(saveLocation));
}
16.05.2016

2
  1. Избавьтесь от ByteArrayOutputStream и Writer и запишите расшифрованные массивы непосредственно в FileOutputStream.
  2. Используйте один и тот же Cipher для всего файла, как при шифровании, так и при расшифровке, и инициализируйте его один раз, а не один раз при чтении.
  3. Вы можете сделать все это примерно в пяти строках кода с расширением CipherInputStream.
16.05.2016
Новые материалы

Учебные заметки JavaScript Object Oriented Labs
Вот моя седьмая неделя обучения программированию. После ruby ​​и его фреймворка rails я начал изучать самый популярный язык интерфейса — javascript. В отличие от ruby, javascript — это более..

Разбор строк запроса в vue.js
Иногда вам нужно получить данные из строк запроса, в этой статье показано, как это сделать. В жизни каждого дизайнера/разработчика наступает момент, когда им необходимо беспрепятственно..

Предсказание моей следующей любимой книги 📚 Благодаря данным Goodreads и машинному обучению 👨‍💻
«Если вы не любите читать, значит, вы не нашли нужную книгу». - J.K. Роулинг Эта статья сильно отличается от тех, к которым вы, возможно, привыкли . Мне очень понравилось поработать над..

Основы принципов S.O.L.I.D, Javascript, Git и NoSQL
каковы принципы S.O.L.I.D? Принципы SOLID призваны помочь разработчикам создавать надежные, удобные в сопровождении приложения. мы видим пять ключевых принципов. Принципы SOLID были разработаны..

Как настроить Selenium в проекте Angular
Угловой | Селен Как настроить Selenium в проекте Angular Держите свое приложение Angular и тесты Selenium в одной рабочей области и запускайте их с помощью Mocha. В этой статье мы..

Аргументы прогрессивного улучшения почти всегда упускают суть
В наши дни в кругах веб-разработчиков много болтают о Progressive Enhancement — PE, но на самом деле почти все аргументы с обеих сторон упускают самую фундаментальную причину, по которой PE..

Введение в Джанго Фреймворк
Схема «работать умно, а не усердно» В этой и последующих статьях я познакомлю вас с тем, что такое фреймворк Django и как создать свое первое приложение с помощью простых и понятных шагов, а..