寻求AES-CTR加密输入

由于CipherOutputStream模式下的AES非常适合随机访问,因此我可以说我在AES-CTR模式下使用CipherOutputStream创建了数据源。 下面的库 – 不是我的 – 使用RandomAccessFile ,它允许寻找文件中的特定字节偏移量。

我最初的想法是使用CipherInputStream和一个使用正确参数初始化的Cipher ,但是它的API不会寻求并声明不支持markreset

我是否错过了可以为我做的这一部分API,我应该查看CTR的IV /块计数器的配置,并使用自定义输入流重新创建它(听起来像针对我self猎枪)或采取我错过的其他方法?

是的,注意到我刚拿到一个Tumbleweed徽章,’yay’……

我最终查找了如何在CTR模式下更新IV。 事实certificate,它为每个处理的AES块做了一个简单的+1。 我按照以下几行实施了阅读。

给定一个实现类似read的方法的类,该方法将读取加密的字节序列中的下一个字节,并且需要支持在该序列中搜索以及以下变量:

  • BLOCK_SIZE :固定为16(128位,AES块大小);
  • cipherjavax.crypto.Cipher一个实例,初始化为处理AES;
  • delegate :包含允许随机访问的加密资源的java.io.InputStream ;
  • input :一个javax.crypto.CipherInputStream我们将提供读取(流将负责解密)。

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个字节)处启动。

unit testing表明这种方法有效(性能基准测试将在未来某个时候完成:))。