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

标签 java encryption aes

我正在写我的学士论文,主题是密码学及其成本。

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

  1. 读取输入文件
  2. 加密输入文件并将其写入新文件。
  3. 读取并解密刚刚写入的加密文件。
  4. 将解密文件的另一个副本写入文件系统。
  5. 比较初始输入文件和解密文件,看看它们是否相同。

它适用于小型 .txt 输入文件。但由于某种原因,它不适用于任何其他类型的文件。如果我将图像作为输入文件,前几个像素是好的,其余的最终会损坏。 据我了解,问题应该出在初始化密码或使用流时。 我还尝试注释掉加密和解密的行,然后它也可以仅制作相同的输入文件的纯副本。

欢迎任何建议,我会尽快测试它们并报告结果。 我对“匈牙利符号”表示歉意。 p 仅用于公共(public),l 用于本地。这就是我们公司的做法。

这是我的类(class):

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

您现有的循环 while (!(lBytesRead < lBytes.length))基本上都是废话。

  • available()显式不是流中的总字节数,并且 Javadoc 中明确指出使用它来分配此类大小的缓冲区的任何用法都是不正确的。同样,你必须循环,见上文。 available(), 的用途很少(如果有的话)。这不是其中之一。

关于java - 在Java中使用CipherOutputStream,加密文件最终损坏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22908767/

相关文章:

java - 在代码中解密 AES 加密的授权 token 方法时 Jar 崩溃。 hs_err _pid 文件提到 arrayof_jbyte_fill

java - 将 HtmlUnit 导入到 Android 项目

java - Proguard 警告 : can't find referenced class scala. *

android - 如何在android中使用Netcipher和Retrofit?

c - 在VC++中使用OpenSSL时具体如何配置?

java - 如何使用 JCE 中的 PBEWITHHMACSHA256ANDAES_256 算法

java - 使用RegEx在html源中查找特定字符串

java - 如何在log4j2中实现自定义模式布局

security - 系统如何知道密码何时包含先前密码的部分内容?

javascript - 如何使用 CryptoJS 使用 AES 算法加密文件?