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

时间:2012-09-28 18:33:17

标签: java encryption stream aes

我使用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);
    }
}

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

1 个答案:

答案 0 :(得分:12)

这非常微妙。您的问题是,在<{1}} 之前,您正在关闭fos 。在您正在执行的cos方法中:

encrypt(...)

关闭} finally { fos.close(); cos.close(); fis.close(); } 下的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(); } } 有一个很棒的org.apache.commons.io.IOUtils方法可以处理closeQuietly(...)次检查并为您捕获例外情况。