Java AES CTR IV和计数器

jar*_*rok 4 java encryption aes initialization-vector

我试着找到答案,自己看这里并在别处搜索了一段时间,但我还是有一些问题.

假设这个Java代码:

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);
}
Run Code Online (Sandbox Code Playgroud)

我的问题是:

  1. 对于CTR模式的计数器更新,上述代码是否正常?具体来说,我不是自己更新计数器.我应该使用以下while循环吗?我试过这个是因为我查看了cipher.getIV()在循环中返回的内容,但它没有改变,getIV()的描述没有详细说明:

        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);
        }
    
    Run Code Online (Sandbox Code Playgroud)
    1. 我有更多与修改的while循环方法有关的问题.以这种方式调用cipher.init()可以吗?我这样做是因为我还没有找到一种方法来更新IV(计数器真的).

    2. 是如此大的块大小还是应该变小?在那种情况下它应该有多大?

Art*_* B. 5

  1. 对于CTR模式的计数器更新,上述代码是否正常?

是.

但是你可能想要调整一下nonce和counter大小.如果你的nonce只有64位长,那么由于生日悖论,你可能会在2 32次加密后遇到nonce冲突(如果接近那个点,概率会增加).如果你对所有这些加密使用相同的密钥(我的意思是消息/文件不是块)并且存在冲突,这被认为是CTR模式的灾难性中断,因为它是两次或多次填充.

您应该考虑使用96位随机数和32位计数器.缺点是您最多只能安全加密2 个32块,每个消息/文件大小为68 GB.

  1. 我有更多与修改的while循环方法有关的问题.以这种方式调用cipher.init()可以吗?

没有.

你真的不应该自己更新计数器.请注意,字节和块密码块之间存在不匹配:建议的计数器更新使用已作为新计数器值处理的字节,其速度比按块计数的自然CTR模式计数器快得多.你正在耗尽计数器,以便更容易发生碰撞.例如,如果在数字表示时,随机数相差1,则如果nonce部分较短且计数器部分较长,则可能发生重叠.如果nonce是96位长,那么你只能安全地加密大小为68/16 GB = 4.5 GB的消息/文件.

此外,由于您的字节/块不匹配,这不再是CTR模式,您将很难将此代码移植到其他语言.

  1. 是如此大的块大小还是应该变小?在那种情况下它应该有多大?

不确定你的意思,AES的固定块大小为128位或16字节.

如果您的意思是输入/输出缓冲区,那么您应该在您选择的平台上对其进行基准测试以确定.它当然看起来不错.