Не удается загрузить весь расшифрованный текстовый файл - PullRequest
0 голосов
/ 01 апреля 2011

Я пишу небольшое тестовое приложение.Дело в том ... Servlet загружает любой зашифрованный файл AES в мое приложение на рабочем столе.Затем мое настольное приложение расшифровывает его и сохраняет на локальном жестком диске.Он работает нормально, как для двоичного видео, изображений и т. Д., Но по какой-то причине я теряю символы из текстовых файлов.Насколько я понимаю, в любом текстовом файле отсутствуют 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);

и метод WriteStreamBody 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)?

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

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

Ответы [ 2 ]

1 голос
/ 02 апреля 2011

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

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

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

1 голос
/ 02 апреля 2011

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

Создает этот файл:

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]));
    }

}
...