As AES in CTR mode is great for random access, lets say I have a data source created with a CipherOutputStream
in AES-CTR mode. The library underneath—which is not mine—uses a RandomAccessFile
that allows to seek to a specific byte offset in the file.
My initial thought would be to use a CipherInputStream
with a Cipher
initialized with the right parameters, but the API for that doesn't do seeking and states to not support mark
and reset
.
Is there a part of the API that I've missed that can do this for me, should I look into the configuration of CTR's IV/block counter and recreate that with a custom input stream (which sounds like shotgun aimed at self
to me) or take some other approach I've missed?
Right, noticed I just got a Tumbleweed badge for this, 'yay'...
I ended up looking up exactly how the IV is updated in CTR mode. This turns out to do a simple +1 for each AES block it processes. I implemented reading along the following lines.
Given a class that implements a
read
-like method that would read the next byte in a byte sequence that is encrypted and needs to support seeking in that sequence and the following variables:BLOCK_SIZE
: fixed at 16 (128 bits, AES block size);cipher
: an instance ofjavax.crypto.Cipher
, initialized to deal with AES;delegate
: ajava.io.InputStream
that wraps an encrypted resource that allows random access;input
: ajavax.crypto.CipherInputStream
we'll be serving reads from (the stream will take care of the decryption).The
seek
method is implemented as such:Note that seeking the delegate resource is omitted here, as this depends on what is underneath the delegate
InputStream
. Also note that the initial IV is required to be started at counter 1 (the last 4 bytes).Unittests show that this approach works (performance benchmarks will be done at some point in the future :)).