Java AES CTR IV and counter

Viewed 11291

I have tried to find the answer by myself looking here and searching elsewhere for quite a while, but I still have some questions.

Assume this Java code:

try
{   
    int cipherMode = Cipher.ENCRYPT_MODE;

    SecretKeySpec secretKey = ...; // generated previously using KeyGenerator       

    byte[] nonceAndCounter = new byte[16];
    byte[] nonceBytes      = ...; // generated previously using SecureRandom's nextBytes(8);

    // use first 8 bytes as nonce
    Arrays.fill(nonceAndCounter, (byte) 0);
    System.arraycopy(nonceBytes, 0, nonceAndCounter, 0, 8);

    IvParameterSpec ivSpec = new IvParameterSpec(nonceAndCounter);
    Cipher cipher = Cipher.getInstance("AES/CTR/NoPadding");

    cipher.init(cipherMode, secretKey, ivSpec);

    File inFile  = new File(...);
    File outFile = new File(...);

    long bytesRead = 0;

    try (FileInputStream is = new FileInputStream(inFile);
         FileOutputStream os = new FileOutputStream(outFile))
    {       
        byte[] inBuf       = new byte[512 * 1024];
        byte[] outBuf      = new byte[512 * 1024];
        int    readLen     = 0;

        ByteBuffer byteBuffer = ByteBuffer.allocate(8);
        byteBuffer.putLong(bytesRead);

        while ((readLen = is.read(inBuf)) != -1)
        {
            bytesRead += readLen;

            cipher.update(inBuf, 0, readLen, outBuf, 0);

            os.write(outBuf);
        }

        cipher.doFinal(outBuf, 0);
        os.write(outBuf);
        is.close();
        os.close();
    }
    catch (Exception e) {
        System.out.printf("Exception for file: %s\n", e);
    }
} 
catch (Exception e) { 
    System.out.printf("Exception: %s\n", e);
}

My questions are:

  1. Is the above code considered OK regarding counter updates for CTR mode? Specifically, I am not updating the counter myself. Should I use the following while loop instead? I tried this because I looked at what cipher.getIV() returns in the loop, but it does not change and the description for getIV() does not go into much details:

        while ((readLen = is.read(inBuf)) != -1)
        {   
            // use offset for last 8 bytes as counter
            byteBuffer.putLong(bytesRead);
            System.arraycopy(byteBuffer.array(), 0, nonceAndCounter, 8, 8);
    
            bytesRead += readLen;
    
            IvParameterSpec ivSpec = new IvParameterSpec(nonceAndCounter);
    
            cipher.init(cipherMode, secretKey, ivSpec);
    
            cipher.update(inBuf, 0, readLen, outBuf, 0);
    
            os.write(outBuf);
        }
    
    1. I have more questions related to the modified while loop approach. Is it OK to call cipher.init() in such a way? I do this because I haven't found a way to update just IV (counter really).

    2. Is such a large block size OK or should it be made smaller? In that case how big should it be?

2 Answers
Related