Не удается загрузить весь расшифрованный текстовый файл

Я пишу небольшое тестовое приложение. Дело в том... Сервлет загружает любой зашифрованный файл AES в мое настольное приложение. Затем мое настольное приложение расшифровывает его и сохраняет на локальном жестком диске. Он отлично работает с двоичным видео, изображениями и т. Д., Но по какой-то причине я теряю символы из файлов txt. Насколько я понимаю, в любом текстовом файле отсутствуют 128 последних битов (это 15 или 16 последних символов).

Я не знаю, почему это происходит, поэтому мне нужен ваш совет.

Вот код сервлета:

final int BUFFER_SIZE = 4096;
FileInputStream in = new FileInputStream(file);
OutputStream out = response.getOutputStream();
byte buffer[] = new byte[BUFFER_SIZE];

for (int nread = 0; (nread = in.read(buffer)) != -1;) {
    out.write(buffer, 0, nread);
}

out.flush();
out.close();
in.close();

И фрагмент кода настольного приложения:

response = httpclient.execute(httppost);//it is HttpClient 4...
resEntity = response.getEntity();
InputStream in = resEntity.getContent();
in = new CipherInputStream(in, decipher);//maybe the aes block missing here...
FileOutputStream out= new FileOutputStream(path);
byte[] buffer = new byte[4096];
int numRead = 0;

while ((count = in.read(buffer)) != -1) {
    out.write(buffer, 0, count);
}

out.flush();
out.close();

И вот как я получаю расшифровку:

KeyGenerator kgen = KeyGenerator.getInstance("AES");
          kgen.init(128);
          key = kgen.generateKey();

    byte[] ivar = new byte[]
                      {
                          0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
                  };
AlgorithmParameterSpec params = new IvParameterSpec(ivar );
dcipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
dcipher.init(Cipher.DECRYPT_MODE, key, params );

... А вот фрагмент загрузки десктопного приложения

HttpPost httppost = null;
        HttpResponse response=null;
        HttpEntity resEntity=null;

        try {
          File file = filePath;
          fileLength=file.length();

          HttpClient httpclient = new DefaultHttpClient();
          httpclient.getParams().setParameter(CoreProtocolPNames.
                                              PROTOCOL_VERSION,
                                              HttpVersion.HTTP_1_1);


          String url="http://localhost:8080/testUrl";
          httppost = new HttpPost(url);

String name=file.getName();
InputStreamBody inputStreamBody=new InputStreamBody(new FileInputStream(file),name);

MultiPartEntity multiPartEntity = new MultiPartEntity();
multiPartEntity .addPart("file-name", new StringBody(name, Charset.forName("UTF-8")));
multiPartEntity .addPart("file-stream", inputStreamBody);

и метод записи InputStreamBody (вы можете увидеть документ здесь http://hc.apache.org/httpcomponents-client-ga/httpmime/clover/org/apache/http/entity/mime/content/InputStreamBody.html). ..

    byte[] ivar = new byte[]
                      {
                              0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
                      };

    ...
    AlgorithmParameterSpec params = new IvParameterSpec(ivar);

    encipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    encipher .init(Cipher.ENCRYPT_MODE, key, params);

...

public void writeTo(final OutputStream out) throws IOException {
              if (out == null) {
                  throw new IllegalArgumentException("Output stream may not be null");
              }
              try {

              out = new CipherOutputStream(out, encipher );


              int numRead = 0;
              while ( (count = in.read(buf)) !=-1) {
                out.write(buf, 0, count);


              }
              out.flush();
              in.close();

            }
            catch (java.io.IOException e) {
            }
          }

Помогите, пожалуйста, с проблемой расшифровки. Возможно, в бинарных файлах тоже не хватает 128 бит, но это не так уж примечательно, за исключением содержимого текстовых файлов :( Я слышал, что это может произойти из-за закрытия потоков неправильной последовательности или около того, но я не уверен.

Я слышал, что это может быть проблема с длиной содержимого InputStreamBody, метод:

public long getContentLength() {

             return -1;


         }

Но как правильно установить измененную длину вывода, если "in.length!=out.length" из-за шифрования (см. метод writeTo)?

Пожалуйста, помогите мне исправить это

Любой полезный комментарий приветствуется :)


person user592704    schedule 01.04.2011    source источник
comment
Не могли бы вы предоставить нам образец файла?   -  person Paŭlo Ebermann    schedule 01.04.2011
comment
А, прикрепить файл не получается. Если он достаточно мал, закодируйте его в base64 и выложите исходник, а лучше выложите куда-нибудь и выложите ссылку. Или выложите программу, создавшую файл.   -  person Paŭlo Ebermann    schedule 01.04.2011
comment
Почему в файле потеряны символы?   -  person user592704    schedule 02.04.2011
comment
Я не понимаю... Почему видео и даже doc-файлы у меня скачиваются нормально, кроме формата txt? Является ли формат txt чем-то особенным?   -  person user592704    schedule 02.04.2011
comment
никогда не пишите catch (java.io.IOException e) {} - это просто съест ваше исключение, и вы не узнаете, что это такое. Используйте как минимум что-то вроде catch (java.io.IOException e) { e.printStackTrace(); } (и посмотрите, есть ли что-то на выходе ошибки).   -  person Paŭlo Ebermann    schedule 02.04.2011
comment
Вы создали подкласс InputStreamBody, в котором вы перезаписали метод, или вы скопировали класс и изменили метод? (То, что вы связали, - это не документация, а представление исходного кода с отчетом о покрытии модульного теста.)   -  person Paŭlo Ebermann    schedule 02.04.2011
comment
Нет, я только что создал класс, который расширяет InputStreamBody.   -  person user592704    schedule 02.04.2011
comment
Но что касается этого случая, да, это сам модифицированный InputStreamBody... Потому что мне нужно было проверить его более тщательно, потому что я не понимаю, почему файлы txt никогда не получают свои окончания :(   -  person user592704    schedule 02.04.2011
comment
Так что вы думаете, что может быть исключение?   -  person user592704    schedule 02.04.2011
comment
Я проверил блок catch, но исключений нет :( Итак, я попытался проверить переданные биты буфера ... загрузка отправляет 553, а загрузка получает 496 + 32 (всего 528). Таким образом, при загрузке теряется около 25 байтов. :( О боже... Где это может быть?   -  person user592704    schedule 02.04.2011
comment
О, я только что заметил, что на стороне сервлета, если файл txt загружен, самый тип контента не завершен, как: Content Type =multipart/form-data; граница = u_UM6G3ECVB-m_MX8Ia_rpYZ33sZjL-NE2lY9_   -  person user592704    schedule 02.04.2011
comment
И, например, граница типа содержимого файла документа: Content Type =multipart/form-data; граница = BevJt9X-12tg8-uJnBfwBEK9_1y8xl   -  person user592704    schedule 02.04.2011
comment
Что это может быть? Почему текстовый файл делает границу незавершенной? Или чего-то не хватает?   -  person user592704    schedule 02.04.2011
comment
Граница — это просто строка, которая ограничивает части составного сообщения, она может быть чем угодно, если только она не появляется внутри самих частей. Он создается более или менее случайным образом программой загрузки. Если у вас есть полный снимок загруженных данных, вы должны увидеть его между отдельными частями и в конце.   -  person Paŭlo Ebermann    schedule 02.04.2011
comment
Вы можете попробовать мою программу, чтобы сначала зашифровать ваш файл на диск, а затем отправить зашифрованный файл с помощью вашей программы загрузки (удалить часть шифрования). Затем вы можете увидеть, есть ли какая-то проблема с шифрованием или с загрузкой. И используйте какую-нибудь другую программу, чтобы посмотреть, что вы туда загрузили (например, загрузите это напрямую с помощью scp или чего-то подобного).   -  person Paŭlo Ebermann    schedule 02.04.2011
comment
Но почему это происходит только с текстовыми файлами txt, html и т. д.? Но doc-файлы в порядке? я не понимаю :(   -  person user592704    schedule 03.04.2011
comment
В качестве теста я просто отключил код шифрования и дешифрования и sonnet126.txt загрузился и скачался отлично :( Так что все же проблема в шифровании и дешифровании... Почему конечный текст теряется? И почему это происходит с только текстовые файлы?   -  person user592704    schedule 03.04.2011
comment
Для меня это настоящая загадка :( Может быть, проблема в кодировке txt (Юникод) или еще в чем-то, но как это может повлиять на шифрование?   -  person user592704    schedule 03.04.2011
comment
возможно, это ошибка синтаксического анализатора загрузки или что-то в этом роде... загрузите код сервлета, например, upload.parseRequest(request); ?   -  person user592704    schedule 03.04.2011
comment
Я отключил код шифрования и дешифрования, и все загружается нормально, даже файлы txt :( Так что это проблема шифрования. Но это происходит только с текстовыми файлами. Я подозреваю, что файлы txt имеют неадаптированную длину битов или что-то в этом роде. .. Итак, остальные биты теряются, потому что в конце нет 4096 бит или я не уверен ... И что мне делать, если это плохая ошибка заполнения?   -  person user592704    schedule 04.04.2011


Ответы (2)


Итак, я сделал тестовую программу, чтобы посмотреть, как она работает (см. ниже).

Он создает этот файл:

O thou, my lovely boy, who in thy power
Dost hold Time's fickle glass, his sickle, hour;
Who hast by waning grown, and therein show'st
Thy lovers withering as thy sweet self grow'st;
If Nature, sovereign mistress over wrack,
As thou goest onwards, still will pluck thee back,
She keeps thee to this purpose, that her skill
May time disgrace and wretched minutes kill.
Yet fear her, O thou minion of her pleasure!
She may detain, but not still keep, her treasure:
Her audit, though delay'd, answer'd must be,
And her quietus is to render thee.

Выглядит полным (и diff говорит, что он идентичен вводу).

Почему ваша программа что-то обрезает, я понятия не имею.

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

Запустите класс в вашем входном файле и сравните его зашифрованный вывод с вашим зашифрованным файлом (как на сервере, так и на клиенте). Возможно, это поможет найти проблему.

Вот пример кода. Основной метод принимает в качестве аргументов три имени файла, первое — исходный файл (и должен существовать), второе — зашифрованный файл, третье — расшифрованный (оба будут перезаписаны, если они существуют). Если задан четвертый аргумент, используется случайный ключ.

package de.fencing_game.paul.examples;

import java.io.*;
import java.security.*;
import java.security.spec.*;
import javax.crypto.*;
import javax.crypto.spec.*;

public class EncryptDecrypt {


    AlgorithmParameterSpec params;

    public EncryptDecrypt()
        throws Exception
    {
        byte[] ivar = new byte[] {
            0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
            0x08, 0x09,0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
        };
        params = new IvParameterSpec(ivar );
    }


    public void encrypt(SecretKey key, File from, File to)
        throws  Exception
    {
        Cipher ourCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        ourCipher.init(Cipher.ENCRYPT_MODE, key, params );
        crypt(ourCipher, from, to);
    }

    public void decrypt(SecretKey key, File from, File to)
        throws Exception
    {
        Cipher ourCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        ourCipher.init(Cipher.DECRYPT_MODE, key, params );
        crypt(ourCipher, from, to);
    }


    private void crypt(Cipher c, File from, File to) 
        throws IOException
    {
        InputStream in = new CipherInputStream(new FileInputStream(from), c);
        OutputStream out = new FileOutputStream(to);
        copyStream(in, out);
    }

    private void copyStream(InputStream in, OutputStream out)
        throws IOException
    {
        byte[] buffer = new byte[4096];
        int count = 0;

        while ((count = in.read(buffer)) != -1) {
            out.write(buffer, 0, count);
        }
        out.flush();
        out.close();
        in.close();
    }


    public static void main(String[] params)
        throws Exception
    {
        EncryptDecrypt ed = new EncryptDecrypt();

        if(params.length > 3) {
            KeyGenerator kgen = KeyGenerator.getInstance("AES");
            kgen.init(128);
            SecretKey key = kgen.generateKey();
        }
        else {
            SecretKeyFactory factory = SecretKeyFactory.getInstance("AES");
            // AES needs 128 bits = 16 bytes
            KeySpec spec =
                new SecretKeySpec("Test-KeyTest-Key".getBytes("US-ASCII"),
                                  "AES");
            System.out.println(spec);

            SecretKey key = factory.generateSecret(spec);
            System.out.println(key);
        }


        ed.encrypt(key, new File(params[0]), new File(params[1]));
        ed.decrypt(key, new File(params[1]), new File(params[2]));
    }

}
person Paŭlo Ebermann    schedule 01.04.2011
comment
хорошо, я проверю это более глубоко. Я подозреваю, что проблема может возникнуть в коде загрузки, но я не уверен, потому что он отлично работает с остальными форматами файлов? Кстати, я использую HttpClient 4 для загрузки файлов ... Может быть, есть спецификация для файлов txt, но я не смог найти информацию? - person user592704; 02.04.2011
comment
Вы используете какую-то программу перевода, которая преобразует окончания строк? (Но тогда я бы исключил, что вывод будет действительно сломан, а не просто отсутствует последняя строка.) - person Paŭlo Ebermann; 02.04.2011
comment
Проверьте размер файла до и после загрузки (и после загрузки, перед расшифровкой). Попробуйте изменить имя файла на что-то вроде .dat или подобное. - person Paŭlo Ebermann; 02.04.2011
comment
Я использую InputStreamBody для загрузки файла с многоформенной сущностью... Существует тип mime по умолчанию — application/octet-stream, так что, может быть, проблема в этом? Но я не уверен... - person user592704; 02.04.2011
comment
код типа... multiPartEntity.addPart(file-stream, new InputStreamBody(new FileInputStream(encryptedFile),encryptedFile.getName())); - person user592704; 02.04.2011
comment
И, да, вы должны быть правы относительно длины, потому что, если вы просто посмотрите на прикрепленный rar-контент более внимательно, вы заметите, что зашифрованный файл меньше, чем исходный, а расшифрованный меньше, чем зашифрованный ... Может быть, шифрование дает сбой с окончательным блок... Как это проверить? - person user592704; 02.04.2011
comment
Как у вас дела с шифрованием? (Если у вас есть код, добавьте его к вопросу.) - person Paŭlo Ebermann; 02.04.2011
comment
Я делаю шифрование прямо внутри метода записи InputStreamBody... Я собираюсь показать вам - person user592704; 02.04.2011
comment
И, кстати, я уже изменил расширение файла с txt на любое другое, например, dat и т. д., но это не помогло... :( - person user592704; 02.04.2011
comment
Я предполагаю, что текстовые файлы довольно маленькие, а двоичные файлы довольно большие? Что является решающим фактором? Что происходит с мегабайтным файлом, содержащим только текст? Что происходит с однопиксельным GIF? - person Simon G.; 03.04.2011
comment
Еще одна мысль. Глядя на код для CipherInputStream и CipherOutputStream, если вы получите BadPaddingException в последнем блоке, вы получите усеченный файл и нигде не увидите видимого исключения. Тот факт, что ваши файлы становятся меньше при каждом проходе через CipherInputStream, может означать, что это проблема заполнения, поскольку заполнение влияет на последний блок. - person Simon G.; 03.04.2011
comment
Как это проверить? Должен ли я сделать несколько тестовых изображений в 1-3 px? Да, видеофайлы большие, и все они получаются хорошо, независимо от их длины около 16,7 МБ и т. Д. Но изображения (например, значки) тоже были в порядке ... Так как же проверить это, чтобы узнать наверняка? - person user592704; 03.04.2011
comment
Хорошо, я собираюсь протестировать большие и маленькие файлы, чтобы сообщить вам более подробную информацию... Но как решить проблему заполнения, если такая вещь имеет место? - person user592704; 03.04.2011
comment
Я проверил и хочу сказать, что изображение 3px повреждено и не может быть открыто, а изображения 5px и 10px в порядке ... В txt-файле 4,4 МБ отсутствуют последние 23 символа :( - person user592704; 03.04.2011
comment
Так что, я думаю, это проблема заполнения... Что вызывает проблему заполнения? И как это исправить в моем случае? - person user592704; 03.04.2011
comment
Помогите пожалуйста понять. - person user592704; 04.04.2011
comment
Вы так и не очень помогли нам выявить причину. Попробуйте изолировать шифрование, загрузку и загрузку, а также расшифровку и следите за размером каждого файла, чтобы увидеть, где файл обрезается. - person Paŭlo Ebermann; 04.04.2011
comment
Что ж, файлы txt усекаются, как я показал в прикрепленных файлах примеров ... Я не знаю, но BadPaddingException не выдает. Это отсечение происходит со всеми текстовыми файлами, такими как txt. html, css и т. д. Файлы 3px png всегда повреждаются после загрузки, но 5px и 10px в порядке. - person user592704; 04.04.2011
comment
Насколько я понимаю, шифрование может шифровать только что заполненные блоки длиной 4096, но не хочет шифровать небольшой оставшийся блок :( Но почему? Почему все выздоравливает, если шифрование происходит без загрузки, как показывает ваш код? - person user592704; 04.04.2011
comment
Пожалуйста, посоветуйте мне тесты, которые я должен сделать, чтобы предоставить более подробную информацию о проверке заполнения, потому что я немного запутался :) - person user592704; 04.04.2011
comment
Цитата: и смотреть после каждого на размер файла, чтобы увидеть, где файл обрезается Я делал это раньше, и я хочу сказать, что шифрование делает файлы txt меньше по их длине. Если я загружаю текстовый файл, а его исходный размер составляет 553 КБ, шифрование создает файл длиной 544 КБ :( - person user592704; 04.04.2011
comment
клиент говорит, что было загружено 553 байта, а сервлет говорит, что было получено 544 байта. Этого не может быть.... но я просто отслеживаю длину чтения и записи байтов во время процесса загрузки и вижу, что... - person user592704; 04.04.2011
comment
Может ли это быть ошибкой на вашем сервере или в загружаемой библиотеке? Вы пробовали перейти на самую новую версию? - person Paŭlo Ebermann; 05.04.2011
comment
Я только что загрузил библиотеки, и я думаю, что это новейшие библиотеки, которые может предоставить apache. - person user592704; 05.04.2011
comment
commons-FileUpload v 1.2.2 и httpComponents v4.1 и commons-io v1.4 - person user592704; 05.04.2011
comment
Я думал, что файлы txt - это первые файлы, которые должны быть без проблем загружены (зашифрованы), потому что они самые простые :) Так что я никогда не ожидал такой неудачи :( - person user592704; 05.04.2011
comment
Конечно, это можно расшифровать, но окончательная текстовая строка выглядит так: Исходный текст: И ее тишина должна передать тебя. Расшифрованный текст: И ее q - person user592704; 05.04.2011
comment
Что касается сервлета, я использую Tomcat 6. - person user592704; 05.04.2011
comment
А как насчет редактирования моего последнего вопроса? Как я могу установить длину контента, если in.length!=out.length ? - person user592704; 05.04.2011
comment
Вам не нужно устанавливать длину - -1 означает, что я еще не знаю длину, определяю ее из конца потока. В качестве альтернативы вы можете сначала зашифровать весь файл, а затем установить длину зашифрованных данных в качестве длины содержимого. Но пока вы не показываете полный пример кода, из которого можно воспроизвести проблему, здесь можно только догадываться. - person Paŭlo Ebermann; 06.04.2011
comment
Возможно, вы правы насчет предварительного шифрования. В любом случае, спасибо, я проверю все советы :) - person user592704; 08.04.2011

Указывает ли ваш код сервлета длину содержимого?

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

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

person Simon G.    schedule 01.04.2011
comment
То есть вы хотите сказать, что я пытаюсь загрузить файл неправильной длины? Но как тогда сделать набивку? - person user592704; 02.04.2011
comment
Эмм... Я шифровал видео и аудио не только длиной 128*N... Но они все разные :) Но в txt файлах всегда не хватает конечного текста... Так что я хочу узнать почему, но мне нужен ваш свежий взгляд. Хорошо, я покажу вам фрагмент кода загрузки... - person user592704; 02.04.2011
comment
Я заметил, что когда я пытаюсь загрузить любой текстовый файл, граница запроса сервлета не завершена. Он заканчивается на _ ... Для файла примера, который я прикрепил, граница: - person user592704; 02.04.2011
comment
составные/данные формы; граница = u_UM6G3ECVB-m_MX8Ia_rpYZ33sZjL-NE2lY9_ - person user592704; 02.04.2011
comment
но если я загружаю файл документа, граница запроса всегда завершается следующим образом: - person user592704; 02.04.2011
comment
составные/данные формы; граница = BevJt9X-12tg8-uJnBfwBEK9_1y8xl - person user592704; 02.04.2011
comment
Цитата: В вашем коде сервлета указана длина контента? да, я использую библиотеку FileUpload, и есть такой код, как ServletFileUpload = new ServletFileUpload(fu.getFileItemFactory()); загрузить.setSizeMax(100000000); - person user592704; 05.04.2011
comment
Итак, я надеюсь, что 100000000 достаточно, чтобы загрузить текстовый файл размером 553 КБ? Или я пропустил длину содержания? - person user592704; 05.04.2011