2013-05-16 27 views
10

CTRモードのAESはランダムアクセスに適しているため、AES-CTRモードでCipherOutputStreamで作成されたデータソースがあるとします。下にあるライブラリ(これは私のものではありません)は、ファイル内の特定のバイトオフセットを探すことを可能にするRandomAccessFileを使用します。AES-CTR暗号化入力を求める

私の最初に考えたのは、右のパラメータで初期化CipherCipherInputStreamを使用することですが、求めているとmarkresetをサポートしないことを述べてthe API for that行いません。

CTRのIV /ブロックカウンタの設定を調べて、カスタム入力ストリーム(これはショットガンのように思える)で再現すると、私にとってはこれができない部分があります。私にはself)、私が逃したいくつかの他のアプローチを取る?

答えて

9

右は、私はIVがCTRモードで更新されます正確にどのように見上げてしまった...「イェーイ」、私はちょうどこのためタンブルウィードのバッジを得た

に気づきました。これは、処理する各AESブロックに対して単純な+1を実行することになります。私は次の行に沿って読書を実装しました。

  • BLOCK_SIZE:固定暗号化され、その配列と以下の変数に求めてサポートするために必要があるバイト列に次のバイトを読んでいましたread様メソッドを実装するクラスを考えると

    16(128ビット、AESブロックサイズ)。

  • cipher:AESを処理するために初期化されたjavax.crypto.Cipherのインスタンス。
  • delegatejava.io.InputStreamランダムアクセスを許可する暗号化されたリソースをラップします。
  • inputjavax.crypto.CipherInputStream(ストリームは復号化を処理します)からの読み取りが行われます。

seek方法は、次のように実装されます。このデリゲートInputStreamの下にあるものに依存としてデリゲート資源を求めているが、ここでは省略されていることを

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 
} 

注意。また、最初のIVはカウンタ1(最後の4バイト)で開始する必要があることにも注意してください。

ユニットテストでは、このアプローチが有効であることが示されています(パフォーマンスベンチマークは、将来、ある時点で実行されます:))。

+1

CTRのカウンタは0に初期化する必要があります。ロールオーバーすると同じキーが同じ 'nonce || 'で再利用される可能性があります。セキュリティのために致命的なCTR値。あなたはそれが起こる前にrekeyingする必要があります。 –

+0

あなたは正しいです、私は私の実装を少し変えて、スペックに実際に合致するようにしました(私が最初に見つけられなかった理由はわかりません...) – akaIDIOT

+0

うん、私はもうコメントを編集できません。 [仕様にしたがってIVのビルドアップへのリンク](http://tools.ietf.org/html/rfc3686#section-4)。 – akaIDIOT