Java 无法下载整个解密的txt文件

Java 无法下载整个解密的txt文件,java,file-io,iostream,encryption,Java,File Io,Iostream,Encryption,我正在编写一个小的测试应用程序。问题是。。。Servlet将任何AES加密文件下载到我的桌面应用程序。然后我的桌面应用程序将其解密并保存在本地硬盘上。对于二进制视频、图像等,它工作得很好,但由于某些原因,我从txt文件中丢失了字符。据我所知,任何txt文件都缺少其128个最终位(它是15或16个最终字符) 我不知道为什么会这样,所以我需要你的建议 以下是servlet代码: final int BUFFER_SIZE = 4096; FileInputStream in = new FileIn

我正在编写一个小的测试应用程序。问题是。。。Servlet将任何AES加密文件下载到我的桌面应用程序。然后我的桌面应用程序将其解密并保存在本地硬盘上。对于二进制视频、图像等,它工作得很好,但由于某些原因,我从txt文件中丢失了字符。据我所知,任何txt文件都缺少其128个最终位(它是15或16个最终字符)

我不知道为什么会这样,所以我需要你的建议

以下是servlet代码:

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方法(您可以在这里看到文档)

请帮我解决解密问题。也许二进制文件也丢失了128位,但除了文本文件内容外,这并没有那么显著:(我听说这可能是因为序列流关闭不正确,但我不确定

我听说可能是InputStreamBody内容长度问题,方法是:

public long getContentLength() {

             return -1;


         }
但是,如果由于加密而导致“in.length!=out.length”,如何正确设置修改后的输出长度(请参见writeTo方法)

请帮我修一下


任何有用的评论都非常感谢:)

所以,我做了一个测试程序,看看它是如何工作的(见下文)

它将创建以下文件:

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
表示它与输入相同)

我不知道为什么你的程序似乎切断了某些东西

您在问题中输入的代码没有编译(需要一些修改,请参见下文),并且还使用随机密钥(来自密钥生成器),而不是用于加密示例文本文件的密钥。我在下面的示例中使用了一个固定密钥,以确保再现性,但使用随机密钥也会生成相同的解密文件(显然是另一个加密文件)

在输入文件上运行该类,并将其加密输出与加密文件(在服务器和客户端上)进行比较。也许这有助于发现问题

这里是示例代码。 main方法使用三个文件名作为参数,第一个是原始文件(并且必须存在),第二个是加密文件,第三个是解密文件(如果存在,两者都将被覆盖)。如果给出第四个参数,它将使用随机键

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

}

servlet代码是否指定了内容长度

缺少的尾随字节将是密码的最后一个块。最后一块始终需要特殊处理,因为它必须填充。填充使加密文件比原始文件大几个字节。如果您的servlet发送实际文件的内容长度,下载将被截断,最终的内容将被不正确地截断,输出将丢失几个字节


您尝试的二进制文件可能是密码块的精确倍数,因此不需要任何填充。

您能给我们一个示例文件吗?啊,文件附加不起作用。如果它足够小,用base64编码并发布源代码,但最好将其上传到某个地方并发布链接。或者发布生成文件的程序。这就是文件丢失字符的原因?我不明白。。。为什么除了txt格式外,我下载的视频甚至文档文件都很好?txt格式有什么特别的吗?好的,我将更深入地检查它。我怀疑上传代码可能会出现问题,但我不确定,因为它可以与rest文件格式一起正常工作?顺便说一下,我正在使用HttpClient 4上载文件。。。可能有txt文件的规范,但我找不到相关信息?您是否使用转换行尾的传输程序?(但我会在上传前后(下载后,解密前)检查文件大小。尝试将文件名更改为
.dat
之类的名称。我正在使用InputStreamBody上载具有多种形式实体的文件。。。有一个默认的mime类型是application/octet stream,所以这可能是问题所在?但我不确定…代码就像。。。addPart(“文件流”,新的InputStreamBody(新的FileInputStream(encryptedFile),encryptedFile.getName());所以你想说我试图上传一个长度错误的文件?那怎么做软垫呢?嗯。。。我加入了视频和音频,不仅仅是128*N的长度。。。但是它们都不同:)但是txt文件总是缺少一些最终文本。。。所以我想知道为什么,但我需要你的新视力。好的,我将向您展示上传代码片段……我注意到,当我尝试上传任何txt文件时,servlet请求边界尚未完成。它以“u”结尾。。。对于我所附的示例文件,边界是:“多部分/表单数据;边界=u_UM6G3ECVB-m_MX8Ia_rpYZ33sZjL-NE2lY9”,但如果我上传一个文档文件,请求边界总是像以下一样完成:
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]));
    }

}