How to handle the IV/Nonce/Counter for AES CTR?
Asked Answered
F

1

2
import javax.crypto.Cipher;

public abstract class Crypto {


    private static final String CIPHER_ALGORITHM = "AES/CTR/NoPadding";
    private String AesKeyString = "ByWelFHCgFqivFZrWs89LQ==";

    private void setKey() throws NoSuchAlgorithmException{
        byte[] keyBytes;
        keyBytes = Base64.getDecoder().decode(AesKeyString);
        aesKey = new SecretKeySpec(keyBytes, "AES");
    }

    protected byte[] execute(int mode, byte[] target, byte[] iv) 
            throws Exception{
        Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
        IvParameterSpec ivSpec = new IvParameterSpec(iv);
        cipher.init(mode, aesKey, ivSpec);
        return cipher.doFinal(target);
    }

}

According to NIST Recommendation - Appendix B, there are two valid approaches to construct the initial counter blocks (AES is a 128-bit block cipher):

  1. 128-bit nonce XORed with an m-bit counter value (usually 32 bits).
  2. 64-bit nonce prepended to a 64-bit counter.

My question is:

  • What is the exact procedure regarding the initial counter block used in an "AES/CTR/NoPadding" instance of javax.crypto.Cipher (assuming SunJCE as the provider)? That is, given the above code, which of the previous approaches for the initial counter block is used, if any?
Flunk answered 16/3, 2017 at 14:25 Comment(2)
@MaartenBodewesFlunk
That doesn't work everywhere, only at the places where I posted a comment, but hey, no problem, Artjom took care of that :)Ichthyornis
I
4

Java simply leaves the choice of the way you construct the counter to you. You simply have to initialize the CTR mode using a 16 byte IV, which is nothing more than the initial counter value.

Once you start encrypting it will use a counter over the full 128 bits. Then again, you would hardly want it to start over as that would directly compromise the security of the plaintext. The disadvantage is that the 32 bit XOR method is not directly supported (if you start with a a counter of FFFFFFFF the next value will alter the 33rd least significant bit of the counter).

Then again, I would rather choose a 8-byte nonce and leave the least significant bits set to all zeros. Or choose GCM mode of course.


Proof:

Cipher aesCTR = Cipher.getInstance("AES/CTR/NoPadding");
SecretKey aesKey = new SecretKeySpec(new byte[16], "AES");
IvParameterSpec lastIV = new IvParameterSpec(Hex.decode("FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF"));
aesCTR.init(Cipher.ENCRYPT_MODE, aesKey, lastIV);
byte[] twoBlocks = aesCTR.doFinal(new byte[2 * aesCTR.getBlockSize()]);
byte[] secondBlock = Arrays.copyOfRange(twoBlocks, 16, 32);
System.out.printf("%s%n", Hex.toHexString(secondBlock));

IvParameterSpec firstIV = new IvParameterSpec(new byte[16]); // all zero IV
aesCTR.init(Cipher.ENCRYPT_MODE, aesKey, firstIV);
byte[] oneBlock = aesCTR.doFinal(new byte[aesCTR.getBlockSize()]);
System.out.printf("%s%n", Hex.toHexString(oneBlock));

Output:

66e94bd4ef8a2c3b884cfa59ca342b2e
66e94bd4ef8a2c3b884cfa59ca342b2e
Ichthyornis answered 16/3, 2017 at 20:3 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.