【发布时间】: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