【问题标题】:Buffering reads from a CipherInputStream缓冲来自 CipherInputStream 的读取
【发布时间】:2013-12-16 23:29:15
【问题描述】:

我遇到了需要缓冲 CipherInputStream 的情况。确切地说,在将结果返回给 InputStream.read(byte[], int, int) 的调用者之前,我需要确保缓冲区已填充到 32K 或达到 EOF。在这里,我遇到了一些障碍,希望大家能提供帮助。

  • Oracle JRE - CipherInputStream 有一个 512 字节的内部缓冲区,用于 没有特别的理由。
  • IBM JRE - CipherInputStream 有一个内部缓冲区 8KB

简单地用 BufferedInputStream 包装 CipherInputStream 并没有给我任何好处,因为 CipherInputStream.available() 将返回 0,这使得缓冲毫无意义。 CipherInputStream 的 javadoc 声明这应该被子类 http://docs.oracle.com/javase/7/docs/api/javax/crypto/CipherInputStream.html#available() 覆盖

由于我正在处理 FileInputStream(在大多数情况下)作为我的最低级别流,并且我的密码算法是没有填充的 CTR,因此我在加密前和加密后具有相同数量的字节,但这就是事情的开始让我变得模糊。我已经覆盖了 CipherInputStream.available() 以返回 super.available(),这似乎对使用 Oracle 的 CipherInputStream 的本地文件非常有效。

我可以确保我的 32K 缓冲区充满了对 read(byte[], int, int) 的调用,或者到达了文件末尾。

使用 Oracle JRE 输出

**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

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

使用 IBM JRE 输出

**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
        }
    }
}

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

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

【问题讨论】:

  • 仅作记录,多年后:available() javadoc 在上面没有被完全正确地引用。 CipherInputStream 的 javadoc 说 InputStream#available() 基类返回零,并且 因此 它应该被覆盖。 CipherInputStream 本身确实提供了覆盖实现; Oracle/OpenJDK 版本只有一行:return (ofinish - ostart);,它们只是已解密但尚未read() 的缓冲区的偏移量。

标签: java oracle encryption buffer


【解决方案1】:

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

【讨论】:

  • 您是否在 OP 的上下文中对此进行了测试? ;D
  • 我在十多年的时间里在几十个环境中测试过它,我还阅读了要求它可以工作的Javadoc。
  • 您能否在回答中参考 javadoc?
猜你喜欢
  • 1970-01-01
  • 2013-12-14
  • 2012-08-20
  • 2020-06-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多