在Java中使用CipherOutputStream,加密文件最终会损坏

在Java中使用CipherOutputStream,加密文件最终会损坏,java,encryption,aes,Java,Encryption,Aes,我正在写一篇关于密码学及其成本的学士论文 其中一部分是从运行时间和资源成本方面比较不同的加密算法和密码模式。 为此,我编写了一个小工具,它应该分为四个步骤: 读取输入文件 加密输入文件并将其写入新文件 读取并解密刚刚写入的加密文件 将解密文件的另一个副本写入文件系统 比较初始输入文件和解密文件,看它们是否相等 它只需要一个小的.txt输入文件就可以正常工作。但由于某些原因,它不适用于任何其他类型的文件。如果我把一个图像作为输入文件,前几个像素是好的,其余的都被破坏了。 据我所知,问题应该是在初始

我正在写一篇关于密码学及其成本的学士论文

其中一部分是从运行时间和资源成本方面比较不同的加密算法和密码模式。 为此,我编写了一个小工具,它应该分为四个步骤:

  • 读取输入文件
  • 加密输入文件并将其写入新文件
  • 读取并解密刚刚写入的加密文件
  • 将解密文件的另一个副本写入文件系统
  • 比较初始输入文件和解密文件,看它们是否相等
  • 它只需要一个小的.txt输入文件就可以正常工作。但由于某些原因,它不适用于任何其他类型的文件。如果我把一个图像作为输入文件,前几个像素是好的,其余的都被破坏了。 据我所知,问题应该是在初始化密码或使用流时出现的。 我还试着对加密和解密的行进行注释,然后它也可以只制作相同的输入文件的普通副本

    欢迎提出任何建议,我将尽快测试它们,并报告结果。 我为“匈牙利符号”道歉。p仅用于公共,l用于本地。这是我们公司的做法

    这是我的课:

    import java.io.File;
    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.security.InvalidAlgorithmParameterException;
    import java.security.InvalidKeyException;
    import java.security.Key;
    import java.security.NoSuchAlgorithmException;
    import java.util.Arrays;
    import java.util.Date;
    import javax.crypto.Cipher;
    import javax.crypto.CipherInputStream;
    import javax.crypto.CipherOutputStream;
    import javax.crypto.KeyGenerator;
    import javax.crypto.NoSuchPaddingException;
    import javax.crypto.spec.IvParameterSpec;
    
    
    public class AES_Cipher_Test {
    
    
        public String pLocalRef = "E:\\Test.txt";
        public String pLocalRefOutput = "E:\\Test-crypted.txt";
        public String pLocalCopyOutput = "E:\\Test-Neu.txt";
        public Key pKeyAES = null;
        public int pBitKey = 128;
        public Cipher pCipher;  
        public FileOutputStream pFos;
        public FileInputStream pFis;
        public CipherOutputStream pCos;
        public CipherInputStream pCis;
        public File pInputFile = new File(this.pLocalRef);
        public File pOutputFile = new File(this.pLocalRefOutput);
        public File pGeneratedFile = new File(this.pLocalCopyOutput);
    
        public AES_Cipher_Test() {
            crypt_decrypt_write_File();
        }
    
        public void crypt_decrypt_write_File() {
            byte[] lLoadedFile = null;
            byte[] lGeneratedFileByte = null;
            try {
    
                // generate new random AES Key
                KeyGenerator lKeygen = KeyGenerator.getInstance("AES");
                lKeygen.init(this.pBitKey);
                this.pKeyAES = lKeygen.generateKey();
    
    
                // read input File
                this.pFis = new FileInputStream(this.pInputFile);
                FileInputStream tempStream = new FileInputStream(this.pInputFile);
                int count = 0;
                while (tempStream.read() != -1){
                    count ++;
                }
                lLoadedFile = new byte[count]; // new byte[this.pFis.available()]
                this.pFis.read(lLoadedFile);
                System.err.println("lLoadedFile.legth  " + lLoadedFile.length);
                this.pFis.close();
    
                //init Cipher with AES Encrypt Mode CFB8 oder CTR
                this.pCipher = Cipher.getInstance("AES/CTR/PKCS5Padding");
                this.pCipher.init(Cipher.ENCRYPT_MODE, this.pKeyAES);
    
    
                // build cipher stream from FileOutputStream
                this.pFos = new FileOutputStream(this.pOutputFile);
                this.pCos = new CipherOutputStream(this.pFos, this.pCipher);
    
                //write encrypted Data to stream
                this.pCos.write(lLoadedFile);
                this.pCos.close();
                this.pFos.close();
    
                // init Cipher for decrypt Mode
                this.pCipher.init(Cipher.DECRYPT_MODE, this.pKeyAES, new IvParameterSpec(this.pCipher.getIV()));
    
    
                // read just written localFile and decrypt
                this.pFis = new FileInputStream(this.pOutputFile);
                tempStream = new FileInputStream(this.pOutputFile);
                count = 0;
                while (tempStream.read() != -1){
                    count ++;
                }
                byte[] lBytes = new byte[count];// new byte[this.pFis.available()]
                this.pCis = new CipherInputStream(this.pFis, this.pCipher);
                int lBytesRead = this.pCis.read(lBytes);
                while (lBytesRead > -1) {
                    lBytesRead = this.pCis.read(lBytes);
                }
                this.pCis.close();
                this.pFis.close();
                System.err.println("lBytes.length " + lBytes.length);
    
                // write new not crypted File to see if procedure works
                this.pFos = new FileOutputStream(this.pLocalCopyOutput);
                this.pFos.write(lBytes);
                this.pFos.close();
    
    
                //compare Input File and Output File
                this.pFis = new FileInputStream(this.pGeneratedFile);
                tempStream = new FileInputStream(this.pGeneratedFile);
                count = 0;
                while (tempStream.read() != -1){
                    count ++;
                }
                lGeneratedFileByte = new byte[count]; // new byte[this.pFis.available()]
                int i = this.pFis.read(lGeneratedFileByte);
                this.pFis.close();
    
                System.err.println("lGeneratedFileByte.length " + i);
                System.err.println("Test if initial File and new File are identical = " + Arrays.equals(lGeneratedFileByte, lLoadedFile));
    
    
            } catch (FileNotFoundException e) {
                throw new RuntimeException("FILE_DOES_NOT_EXIST", e);
            } catch (NoSuchAlgorithmException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (NoSuchPaddingException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (InvalidKeyException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (InvalidAlgorithmParameterException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    
    
        public static void main(String args[]) {
            System.err.println("Start AES_Cipher_Test");
            long start = new Date().getTime();
            new AES_Cipher_Test();
            long runningTime = new Date().getTime() - start;
            System.err.println("End AES_Cipher_Test");
            System.err.println("Runtime: " + runningTime);
    
        }
    }
    

    常见的一系列错误

    • 未指定
      read()
      来填充缓冲区。它只指定传输至少一个字节,否则返回-1表示流的结束。您必须循环:

      while ((count = in.read(buffer)) > 0)
      {
          out.write(buffer, 0, count);
      }
      
    您现有的循环
    而(!(lBytesRead
    基本上是无意义的

    • available()
      显式地不是流中的总字节数,任何使用它来分配如此大小的缓冲区的方法都在Javadoc中显式地声明为不正确。同样,您必须循环,请参见上文。
      available(),
      的用法很少,这不是其中之一

    在注释加密和解密文件的两行代码时,我得到了一个没有损坏的纯拷贝,忘了提到这一部分……它们到底是哪两行?在我看来,还不止这些。在任何情况下,报告在进行上述更正时发生的情况都会更有趣。它们不是可选的:它们是强制性的。去掉“this.pCos=new CipherOutputStream(this.pFos,this.pCipher);”和“this.pCis=new cipheriputstream(this.pFis,this.pCipher);”这两行,当然会对其进行编辑,以使FileInputStream/FileOutputStream读写,并且只生成文件副本。read()和available()没有问题@user3497703您没有抓住要点。我不在乎。按照这里的建议修复代码,然后告诉我们如果仍然有问题会发生什么。按照建议进行编辑(希望如此),问题不会改变。在Java中永远不要使用匈牙利符号。这完全没有必要。Java标识符的类型可以通过读取其声明来确定。Java有一个样式指南。。。如果你想让其他人阅读你的代码,你应该遵循它。你对循环的编辑
    while(lBytesRead@StephenC)很抱歉这些符号,但我必须使用它们,公司标准…@jonny-真的吗?真是个糟糕的主意。