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

时间:2014-04-07 09:42:54

标签: java encryption aes

我正在学习关于密码学及其成本主题的学士论文。

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

  1. 读取输入文件
  2. 加密输入文件并将其写入新文件。
  3. 读取并解密刚编写的加密文件。
  4. 将解密文件的另一个副本写入文件系统。
  5. 比较初始输入文件和解密文件,看它们是否相等。
  6. 使用小的.txt输入文件可以正常工作。但由于某种原因,它不适用于任何其他类型的文件。如果我将图像作为输入文件,前几个像素是好的,其余像素被破坏。 因此,据我所知,当我初始化密码或使用Streams时,问题应该是某种方式。 我还尝试对加密和解密的行进行注释,然后它也可以只生成相同的输入文件的纯文本副本。

    欢迎提出任何建议,我会尽快测试它们并报告显示的结果。 我为“匈牙利符号”道歉。 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);
    
        }
    }
    

1 个答案:

答案 0 :(得分:1)

常见的一系列错误。

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

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

您现有的循环while (!(lBytesRead < lBytes.length))基本上是无意义的。

  • available()显式不是流中的总字节数,并且在Javadoc中明确声明任何使用它来分配这种大小的缓冲区都是不正确的。同样,你必须循环,见上文。 available(),的使用很少,而且不是其中之一。