2
votes

There is a very good example for random access AES CTR mode and it works: Random access InputStream using AES CTR mode in android

private static final int AES_BLOCK_SIZE = 16;
private static IvParameterSpec calculateIVForOffset(final IvParameterSpec iv,
    final long blockOffset) {
final BigInteger ivBI = new BigInteger(1, iv.getIV());
final BigInteger ivForOffsetBI = ivBI.add(BigInteger.valueOf(blockOffset
        / AES_BLOCK_SIZE));

final byte[] ivForOffsetBA = ivForOffsetBI.toByteArray();
final IvParameterSpec ivForOffset;
if (ivForOffsetBA.length >= AES_BLOCK_SIZE) {
    ivForOffset = new IvParameterSpec(ivForOffsetBA, ivForOffsetBA.length - AES_BLOCK_SIZE,
            AES_BLOCK_SIZE);
} else {
    final byte[] ivForOffsetBASized = new byte[AES_BLOCK_SIZE];
    System.arraycopy(ivForOffsetBA, 0, ivForOffsetBASized, AES_BLOCK_SIZE
            - ivForOffsetBA.length, ivForOffsetBA.length);
    ivForOffset = new IvParameterSpec(ivForOffsetBASized);
}

return ivForOffset;
}

However, it doesn't work on AES GCM mode. I am getting garbage when decrypted. I am not encryption expert and was trying to crack it for couple days already. Maybe anyone can give any insight on it? My guess I need to change the IV calculation for offset somehow or it is something to do with an auth Tag (which I am not using).

2

2 Answers

3
votes

GCM mode uses counter mode for confidentiality. So it is possible to decrypt the ciphertext without authentication; take a look at my answer here. To encrypt or decrypt from a given offset you can alter the counter to alter the bytes for the given offset and XOR the resulting ciphertext. However, you would be unable to verify any ciphertext if you skip even a single byte.

So with GCM it is better to divide the plaintext into chunks and encrypt those separately.

0
votes

AES GCM uses a mode called GCTR. It's CTR-like, but is defined in a very specific way.

When the IV is not 12 bytes, it is first hashed to get a 12-byte IV (the GHASH function is specified as a single multiplication with the Galois field, the same one used for the MAC).

Then the 12-byte IV is concatenated with a 4-byte counter (starting from 1), to get the 16-byte CTR block.

So treating the IV as a BigInteger and incrementing it like you do in your example will definitely not work.