由于 CTR 模式下的 AES 非常适合随机访问,假设我有一个使用CipherOutputStream
在 AES-CTR 模式下。下面的图书馆(不是我的)使用RandomAccessFile
允许查找文件中的特定字节偏移量。
我最初的想法是使用CipherInputStream
with a Cipher
使用正确的参数初始化,但是的API http://docs.oracle.com/javase/7/docs/api/javax/crypto/CipherInputStream.html不寻求并声明不支持mark
and reset
.
我是否错过了 API 的一部分可以为我做到这一点,我是否应该研究 CTR 的 IV/块计数器的配置并使用自定义输入流重新创建它(这听起来像是瞄准目标的霰弹枪)self
对我来说)或采取我错过的其他方法?
我最终查明了 IV 在 CTR 模式下是如何更新的。结果是对其处理的每个 AES 块执行简单的 +1。我按照以下思路实施阅读。
给定一个实现了read
类似于方法,该方法将读取加密的字节序列中的下一个字节,并且需要支持在该序列和以下变量中查找:
-
BLOCK_SIZE
:固定为 16(128 位,AES 块大小);
-
cipher
: 的一个实例javax.crypto.Cipher
,初始化为处理 AES;
-
delegate
: a java.io.InputStream
包装允许随机访问的加密资源;
-
input
: a javax.crypto.CipherInputStream
我们将提供读取服务(流将负责解密)。
The seek
方法的实现如下:
void seek(long pos) {
// calculate the block number that contains the byte we need to seek to
long block = pos / BLOCK_SIZE;
// allocate a 16-byte buffer
ByteBuffer buffer = ByteBuffer.allocate(BLOCK_SIZE);
// fill the first 12 bytes with the original IV (the iv minus the actual counter value)
buffer.put(cipher.getIV(), 0, BLOCK_SIZE - 4);
// set the counter of the IV to the calculated block index + 1 (counter starts at 1)
buffer.putInt(block + 1);
IvParameterSpec iv = new IvParameterSpec(buffer.array());
// re-init the Cipher instance with the new IV
cipher.init(Cipher.ENCRYPT_MODE, key, iv);
// seek the delegate wrapper (like seek() in a RandomAccessFile and
// recreate the delegate stream to read from the new location)
// recreate the input stream we're serving reads from
input = new CipherInputStream(delegate, cipher);
// next read will be at the block boundary, need to skip some bytes to arrive at pos
int toSkip = (int) (pos % BLOCK_SIZE);
byte[] garbage = new byte[toSkip];
// read bytes into a garbage array for as long as we need (should be max BLOCK_SIZE
// bytes
int skipped = input.read(garbage, 0, toSkip);
while (skipped < toSkip) {
skipped += input.read(garbage, 0, toSkip - skipped);
}
// at this point, the CipherStream is positioned at pos, next read will serve the
// plain byte at pos
}
请注意,此处省略了寻找委托资源,因为这取决于委托下方的内容InputStream
。另请注意,初始 IV 需要从计数器 1(最后 4 个字节)开始。
单元测试表明这种方法是有效的(性能基准将在未来的某个时候进行:))。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)