CipherInputStream只读取16个字节(AES/Java)

Jos*_*hua 9 java encryption aes stream

我正在使用CipherInputStream和CipherOutputStream来使用AES加密文件.

encrypt(...)似乎工作正常,但我的decrypt(...)函数只解密我的文件的前16个字节.

这是我的班级:

public class AESFiles {

    private byte[] getKeyBytes(final byte[] key) throws Exception {
        byte[] keyBytes = new byte[16];
        System.arraycopy(key, 0, keyBytes, 0, Math.min(key.length, keyBytes.length));
        return keyBytes;
    }

    public Cipher getCipherEncrypt(final byte[] key) throws Exception {
        byte[] keyBytes = getKeyBytes(key);
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        SecretKeySpec secretKeySpec = new SecretKeySpec(keyBytes, "AES");
        IvParameterSpec ivParameterSpec = new IvParameterSpec(keyBytes);
        cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
        return cipher;
    }

    public Cipher getCipherDecrypt(byte[] key) throws Exception {
        byte[] keyBytes = getKeyBytes(key);
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        SecretKeySpec secretKeySpec = new SecretKeySpec(keyBytes, "AES");
        IvParameterSpec ivParameterSpec = new IvParameterSpec(keyBytes);
        cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec);
        return cipher;
    }

    public void encrypt(File inputFile, File outputFile, byte[] key) throws Exception {
        Cipher cipher = getCipherEncrypt(key);
        FileOutputStream fos = null;
        CipherOutputStream cos = null;
        FileInputStream fis = null;
        try {
            fis = new FileInputStream(inputFile);
            fos = new FileOutputStream(outputFile);
            cos = new CipherOutputStream(fos, cipher);
            byte[] data = new byte[1024];
            int read = fis.read(data);
            while (read != -1) {
                cos.write(data, 0, read);
                read = fis.read(data);
                System.out.println(new String(data, "UTF-8").trim());
            }
            cos.flush();
        } finally {
            fos.close();
            cos.close();
            fis.close();
        }
    }

    public void decrypt(File inputFile, File outputFile, byte[] key) throws Exception {
        Cipher cipher = getCipherDecrypt(key);
        FileOutputStream fos = null;
        CipherInputStream cis = null;
        FileInputStream fis = null;
        try {
            fis = new FileInputStream(inputFile);
            cis = new CipherInputStream(fis, cipher);
            fos = new FileOutputStream(outputFile);
            byte[] data = new byte[1024];
            int read = cis.read(data);
            while (read != -1) {
                fos.write(data, 0, read);
                read = cis.read(data);
                System.out.println(new String(data, "UTF-8").trim());
            }
        } finally {
            fos.close();
            cis.close();
            fis.close();
        }
    }

    public static void main(String args[]) throws Exception {
        byte[] key = "mykey".getBytes("UTF-8");
        new AESFiles().encrypt(new File("C:\\Tests\\secure.txt"), new File("C:\\Tests\\secure.txt.aes"), key);
        new AESFiles().decrypt(new File("C:\\Tests\\secure.txt.aes"), new File("C:\\Tests\\secure.txt.1"), key);
    }
}
Run Code Online (Sandbox Code Playgroud)

所以我的问题是,为什么decrypt函数只读取前16个字节?

Gra*_*ray 12

这非常微妙.你的问题是,你是关闭您fos 之前cos.在您的encrypt(...)方法中,您正在做:

} finally {
    fos.close();
    cos.close();
    fis.close();
}
Run Code Online (Sandbox Code Playgroud)

这样FileOutputStream可以从最低位置关闭,CipherOutputStream因此加密输出的最终填充块永远不会写入输出文件.如果你关闭fos ,cos那么你的代码应该可以正常工作.

真的,你应该考虑这样做:

    FileOutputStream fos = null;
    CipherOutputStream cos = null;
    FileInputStream fis = null;
    try {
        fis = new FileInputStream(inputFile);
        fos = new FileOutputStream(outputFile);
        cos = new CipherOutputStream(fos, cipher);
        // once cos wraps the fos, you should set it to null
        fos = null;
        ...
    } finally {
        if (cos != null) {
           cos.close();
        }
        if (fos != null) {
           fos.close();
        }
        if (fis != null) {
           fis.close();
        }
    }
Run Code Online (Sandbox Code Playgroud)

仅供参考:org.apache.commons.io.IOUtils有一个很好的closeQuietly(...)方法可以处理null检查并捕获异常.

  • 到目前为止,这可以通过使用try-with-resources来处理.请注意,您可以在`try`语句中指定多个流,这些流将自动关闭,当然也会以正确(反向)顺序关闭. (2认同)