首页 > 解决方案 > 如何使用 CipherInputStream 解密文件或为什么以下方法不起作用

问题描述

我有以下功能来加密文件。我打印了两个文件的结果,一切似乎都正常工作。

加密文件已更改,并且与输入文件的长度相同。

public void encrypt(String password, String filePath){
    InputStream is = null;
    OutputStream os = null;
    CipherOutputStream cos = null;
    try {
        is = new FileInputStream(new File(filePath));
        os = new FileOutputStream(new File(filePath + ".enc"));
        char[] passwordChars = password.toCharArray();
        SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
        KeySpec spec = new PBEKeySpec(passwordChars, salt, 1024, 256);
        SecretKey tmp = factory.generateSecret(spec);
        SecretKey key = new SecretKeySpec(tmp.getEncoded(), "AES");
        Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding");
        c.init(Cipher.ENCRYPT_MODE, key, iv);
        cos = new CipherOutputStream(os, c);
        byte[] b = new byte[1024];
        while(is.read(b) != -1)
            cos.write(b);
            b = new byte[1024];
        }
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        try {
            if (os != null)
                os.close();
            if (is != null)
                is.close();
            if (cos != null)
                cos.close();
        } catch (IOException e) {

        }
    }
}

之后我尝试解密文件时会出现问题。我使用具有以下功能的 CipherInputStream:

public void decrypt(String password, String filePath){   
    InputStream is = null;
    OutputStream os = null;
    CipherInputStream cis = null;
    try {
        is = new FileInputStream(new File(filePath));
        os = new FileOutputStream(new File(filePath + ".dec"));
        char[] passwordChars = password.toCharArray();
        SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
        KeySpec spec = new PBEKeySpec(passwordChars, salt, 1024, 256);
        SecretKey tmp = factory.generateSecret(spec);
        SecretKey key = new SecretKeySpec(tmp.getEncoded(), "AES");
        Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding");
        c.init(Cipher.DECRYPT_MODE, key, iv);
        cis = new CipherInputStream(is, c);
        byte[] b = new byte[1024];
        while(cis.read(b) != -1){
            os.write(b);
            b = new byte[1024];
        }
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        try {
            if (os != null)
                os.close();
            if (is != null)
                is.close();
            if (cis != null)
                cis.close();
        } catch (IOException e) {

        }
    }
}

根本没有进入while循环。当我验证时,它就像文件是空的,但显然不是。加密似乎可以正常工作,但不能解密。

我尝试更改函数以使用 CipherOutputStream 但同样的事情发生了。我得到一个长度为 0 的解密文件。

为什么解密方法不起作用?

标签: javaencryption

解决方案


有很多东西要修复

c.init(Cipher.ENCRYPT_MODE, key, iv);

IV在哪里定义?如果它是静态的,则使用 cbc 模式几乎完全破坏了安全性。

下一步 - 您正在使用没有任何身份验证的 CBC 模式(hmac),尝试搜索“malleable cipher”

为什么解密方法不起作用?

byte[] b = new byte[1024];
    while(is.read(b) != -1)
        cos.write(b);
        b = new byte[1024];
    }

这是完全错误的。无论读取输入如何,您都在写入一个b1024 字节的完整数组。(是否有理由在循环中重新创建数组?)

尝试类似的东西

b=byte[1024];
for(int bytesRead=in.read(b); bytesRead>-1; bytesRead=in.read(b))
   cos.write(b, 0, bytesRead);
 cos.flush()

同样适用于解密,请先修复此问题,然后尝试调试您的应用

注意:我不是很喜欢 CipherStream 实现,我建议你使用cipher.updatecipher.doFinal


推荐阅读