Не може да се изтегли целият дешифриран txt файл

Пиша малко тестово приложение. Работата е там... Servlet изтегля всеки AES криптиран файл в моето настолно приложение. След това приложението ми за настолни компютри го дешифрира и записва на локален hdd. Работи добре като за двоично видео, изображения и т.н., но по някаква причина губя знаци от txt файлове. Доколкото мога да разбера, във всеки 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 writeTo (можете да видите документа тук 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
Ето го woofiles.com/dl-237412-jykMVBnT-files.rar   -  person user592704    schedule 01.04.2011
comment
Защо файлът има загубени знаци?   -  person user592704    schedule 02.04.2011
comment
Не разбирам... Защо видео и дори doc файлове се изтеглят добре, освен txt формат? Форматът txt нещо специално ли е?   -  person user592704    schedule 02.04.2011
comment
Дубликат на изтегления txt файл става свит   -  person BalusC    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
И например граница на тип съдържание на doc файл е: Content Type =multipart/form-data; граница=BevJt9X-12tg8-uJnBfwBEK9_1y8xl   -  person user592704    schedule 02.04.2011
comment
Какво може да бъде? Защо txt файлът прави границата незавършена? Или нещо липсва?   -  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 (Unicode) или нещо друго, но как това може да повлияе на криптирането?   -  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 по подразбиране е приложение/октетен поток, така че може би това е проблемът? Но аз не съм сигурен... - person user592704; 02.04.2011
comment
код като... multiPartEntity.addPart(file-stream, new InputStreamBody(new FileInputStream(encryptedFile),encryptedFile.getName())); - person user592704; 02.04.2011
comment
И да, трябва да сте прав по отношение на дължината, защото ако просто погледнете по-внимателно прикаченото rar съдържание, забелязвате, че криптираният файл е по-малък от оригинала, а декриптираният е по-малък от криптирания... Може би криптирането се проваля с final блокира... Как да го проверя? - person user592704; 02.04.2011
comment
Как правиш криптирането? (Ако имате код, добавете го към въпроса.) - person Paŭlo Ebermann; 02.04.2011
comment
Правя криптирането точно в метода InputStreamBody writeTo... Ще ви покажа - 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,7Mb и т.н.... Но изображенията (като икони) също бяха добре... И така, как да го проверите, за да разберете със сигурност? - person user592704; 03.04.2011
comment
Добре, ще тествам големи и малки файлове, за да ви кажа по-подробна информация... Но как да поправя проблема с подплънките, ако има такова нещо? - person user592704; 03.04.2011
comment
Проверих и искам да кажа, че 3px изображението е повредено и не може да се отвори, а 5px и 10px изображенията са ОК... 4.4Mb txt файл липсват последните 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 файловете по-малки с тяхната дължина. Ако кача txt файл и оригиналната му дължина е 553 Kb, криптирането прави файл с дължина 544 Kb :( - person user592704; 04.04.2011
comment
клиентът казва, че са качени 553 байта, а сървлетът казва, че са получени 544 байта. Това не може да бъде.... но аз просто наблюдавам дължината на четене и запис на байтове по време на процеса на качване и мога да видя, че... - person user592704; 04.04.2011
comment
Възможно ли е това да е грешка във вашия сървър или библиотека за качване? Опитахте ли да промените на най-новата версия? - person Paŭlo Ebermann; 05.04.2011
comment
Току-що изтеглих libs и мисля, че това е най-новият libs, който 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
Забелязах, че когато се опитам да кача който и да е txt файл, границата на заявката за сервлет не е завършена. Завършва с _ ... За примерния файл, който прикачих, границата е: - person user592704; 02.04.2011
comment
multipart/form-data; граница=u_UM6G3ECVB-m_MX8Ia_rpYZ33sZjL-NE2lY9_ - person user592704; 02.04.2011
comment
но ако кача doc файл, границата на заявката винаги е завършена като: - person user592704; 02.04.2011
comment
multipart/form-data; граница=BevJt9X-12tg8-uJnBfwBEK9_1y8xl - person user592704; 02.04.2011
comment
Цитат: Вашият сървлет код указва ли дължина на съдържанието? да, използвам FileUpload lib и има код като ServletFileUpload = new ServletFileUpload(fu.getFileItemFactory()); upload.setSizeMax(100000000); - person user592704; 05.04.2011
comment
Така че се надявам 100000000 да са достатъчни за качване на 553Kb txt файл? Или съм пропуснал дължината на съдържанието? - person user592704; 05.04.2011