Java 缓冲从CipherInputStream读取

Java 缓冲从CipherInputStream读取,java,oracle,encryption,buffer,Java,Oracle,Encryption,Buffer,我遇到了一个需要缓冲CipherInputStream的场景。确切地说,在将结果返回给InputStream.read(字节[],int,int)的调用者之前,我需要确保缓冲区已填充到32K或已达到EOF。这就是我遇到的一个小麻烦,我希望你们都能帮助我 例如,OracleJRE-CipherInputStream有一个512字节的内部缓冲区 没有特别的原因 IBMJRE-CipherInputStream有一个内部缓冲区 8KB的 简单地用BufferedInputStream包装Ciphe

我遇到了一个需要缓冲CipherInputStream的场景。确切地说,在将结果返回给InputStream.read(字节[],int,int)的调用者之前,我需要确保缓冲区已填充到32K或已达到EOF。这就是我遇到的一个小麻烦,我希望你们都能帮助我

  • 例如,OracleJRE-CipherInputStream有一个512字节的内部缓冲区 没有特别的原因
  • IBMJRE-CipherInputStream有一个内部缓冲区 8KB的
简单地用BufferedInputStream包装CipherInputStream不会给我带来任何好处,因为CipherInputStream.available()将返回0,这使得缓冲毫无意义。CipherInputStream的javadoc声明这应该被子类覆盖

由于我将FileInputStream(在大多数情况下)作为我的最低级别的流进行工作,并且我的密码算法是CTR,没有填充,所以我在加密之前和之后有相同的字节数,但这就是我开始变得模糊的地方。我已经重写了CipherInputStream.available()以返回super.available(),这对于使用Oracle的CipherInputStream的本地文件来说似乎非常有效

我可以确保我的32K缓冲区被一个读取调用(byte[],int,int)填满,或者到达文件的末尾

使用oraclejre输出 但是,在IBMs JVM上,似乎跳过了对底层FileInputStream上in.available的调用,这导致了预期返回完整缓冲区或文件结尾的api出现问题。这与在Windows和iSeries上使用IBMJRE的行为相同

使用IBMJRE的输出 代码 我已经尝试创建自己的BufferedInputStream,并更改read(byte[],int,int)方法以不检查包装流的可用()。这样,它将继续读取,直到a)缓冲区已满,或b)到达文件末尾,但我不确定这是否是最佳方法


有没有人对如何解决这个问题有更好的建议或想法?

忘掉available()和所有这些代码。只需将CipherInputStream包装在DataInputStream中,声明一个32k缓冲区,并调用readFully()。两行代码。

您在OP的上下文中测试过吗;在过去的十五年里,DI已经在几十种环境中对它进行了测试,我也阅读了Javadoc,它规定它是有效的。你能在你的答案中引用Javadoc吗?几年后,为了记录在案:上面引用的
available()
Javadoc不是很正确。
cipheriputstream
的javadoc表示
InputStream#available()
基类返回零,因此应该重写它
CipherInputStream
本身提供了一个覆盖实现;Oracle/OpenJDK版本只有一行:
return(ofinish-ostart)
只是将已解密但尚未读取()的内容偏移到缓冲区中。
**CipherInputStream.available: 51121
**CipherInputStream.available: 50609
**CipherInputStream.available: 50097
...
**CipherInputStream.available: 19889
**CipherInputStream.available: 19377
**BufferedInputStream.read: 32768
**CipherInputStream.available: 18353
**CipherInputStream.available: 17841
**CipherInputStream.available: 17329
...
**CipherInputStream.available: 433
**CipherInputStream.available: 0
**BufferedInputStream.read: 18865
**EOF
**CipherInputStream.available: 43441
**CipherInputStream.available: 35249
**CipherInputStream.available: 27057
**BufferedInputStream.read: 32768
(where's the 18865)?
**CipherInputStream.available: 10673
**CipherInputStream.available: 2481
**CipherInputStream.available: 0
**BufferedInputStream.read: 18864
**CipherInputStream.available: 0
**BufferedInputStream.read: 1
EOF
int BUFFER_SIZE = 32768;
BufferedInputStream bis = null;
CipherInputStream cis = null;
try {
    // returns an AES256 CTR cipher with no padding
    Cipher cipher = getCipher();

    cis = new CipherInputStream(fis, cipher) {

        @Override
        public int available() throws IOException {
            // The cipher input stream always returns 0 because
            // in certain implementations (padded ciphers), a
            // standard implementation may not be able to
            // accurately determine the number of available
            // bytes. In our case, however, we are not using a
            // padded cipher and the number of available bytes
            // 'should' be the same as the number available from
            // the underlying stream.

            int available = in.available();
            System.out.println("**CipherInputStream.available: "
                + available);
            return available;
        }
    };
    bis = new BufferedInputStream(cis, BUFFER_SIZE);

    byte[] buf = new byte[BUFFER_SIZE];
    int read = 0;
    while (read >= 0) {
        read = bis.read(buf, 0, BUFFER_SIZE);
        if (read >= 0) {
            System.out.println("**BufferedInputStream.read: " + read);
        }
    }
    System.out.println("EOF");
}
finally {
    if (cis != null) {
        try {
            cis.close();
        }
        catch (IOException exp) {
            // ignore
        }
    }
    if (bis != null) {
        try {
            bis.close();
        }
        catch (IOException exp) {
            // ignore
        }
    }
}