6

I am unable to find any working example for AES CTR encryption for random access. Can someone guide me how to use the counter in CTR MODE also how to implement jumping to a specific position in the stream?

The default stream implementation (CipherInputStream) doesn't skip the stream and it corrupts the plain text.

I am trying to decrypt encrypted Video file stored on sdcard in Android. An embedded HTTP file server decrypts it on the fly. Everything is working fine until a user performs a seek within the video: the video stops immediately because it receives corrupt video stream.

I am using following code to initialize and encrypt/ decrypt stream (for sake of simplicity i hard coded the keys. it will not be hard coded in production)

    ByteBuffer bb = ByteBuffer.allocate(16);
    bb.put("1234567891230000".getBytes());
    byte[] ivString = bb.array();

    // INITIALISATION
    String keyString = "1234567812345678";
    IvParameterSpec iv = new IvParameterSpec(ivString);
    SecretKeySpec keySpec = new SecretKeySpec(keyString.getBytes(), "AES");

    // FOR ENCRYPTION
    Cipher cipher = Cipher.getInstance("AES/CTR/NoPadding");
    cipher.init(Cipher.ENCRYPT_MODE, keySpec, new IvParameterSpec(ivString));
    Inputstream encrypted_is = new CipherInputStream(in, cipher);

    // FOR DECRYPTION
    cipher.init(Cipher.DECRYPT_MODE, keySpec, new IvParameterSpec(ivString));
            Inputstream decrypted_is = new CipherInputStream(in, cipher);
2
  • Try posting some code. It will be easier to help you Commented May 19, 2014 at 17:57
  • "Random access input stream" is a contradiction in terms. It is either random access or a stream. Commented Aug 27, 2014 at 0:31

1 Answer 1

9

You should not implement this using a stream. A stream is used for sequential access to data. Skipping should only be used for jumping short distances forward and mark/reset only for jumping small distances back.

Using a file map is probably the most efficient. For a slightly easier approach but less efficient approach you could use RandomAccessFile instead. You should furthermore use Cipher.getInstance("AES/CTR/NoPadding") using an "IV" that is set to the counter you expect at the location you start within the file.


Sample code for using CTR with offset:

private static final int AES_BLOCK_SIZE = 16;

public static final void jumpToOffset(final Cipher c,
        final SecretKey aesKey, final IvParameterSpec iv, final long offset) {
    if (!c.getAlgorithm().toUpperCase().startsWith("AES/CTR")) {
        throw new IllegalArgumentException(
                "Invalid algorithm, only AES/CTR mode supported");
    }

    if (offset < 0) {
        throw new IllegalArgumentException("Invalid offset");
    }

    final int skip = (int) (offset % AES_BLOCK_SIZE);
    final IvParameterSpec calculatedIVForOffset = calculateIVForOffset(iv,
            offset - skip);
    try {
        c.init(Cipher.ENCRYPT_MODE, aesKey, calculatedIVForOffset);
        final byte[] skipBuffer = new byte[skip];
        c.update(skipBuffer, 0, skip, skipBuffer);
        Arrays.fill(skipBuffer, (byte) 0);
    } catch (ShortBufferException | InvalidKeyException
            | InvalidAlgorithmParameterException e) {
        throw new IllegalStateException(e);
    }
}

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;
}
Sign up to request clarification or add additional context in comments.

8 Comments

1 - I used AES/CTR/NoPadding for encryption.how can i set counter in IV to start from specific value. 2 - How to get plain bytes at a skipped position.(decrypt encrypted block from a specific position). thank you
Can you please quote few lines of implementation. i am coding in Java but unable to find any code snippet.
Ok but thanks alot for taking time to answer my question. Its a big help for me :)
Any progress on this? I am really really stuck.
@frostymarvelous As you asked so nicely.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.