如何处理AES CTR的IV / Nonce / Counter?

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); } } 

根据NIST建议 – 附录B,有两种有效的方法来构造初始计数器块(AES是128位块密码):

  1. 128位随机数与m位计数器值(通常为32位)进行异或。
  2. 64位nonce前置于64位计数器。

我的问题是:

  • 关于javax.crypto.Cipher的“ AES / CTR / NoPadding ”实例中使用的初始计数器块的确切过程是什么(假设SunJCE是提供者)? 也就是说,考虑到上面的代码,使用了以前哪种初始计数器块的方法,如果有的话?

Java只是让你选择构造计数器的方式。 您只需使用16字节IV初始化CTR模式,这只不过是初始计数器值。

一旦开始加密,它将在整个128位上使用计数器。 再说一次,你几乎不想让它重新开始,因为这会直接损害明文的安全性。 缺点是不直接支持32位XOR方法(如果以FFFFFFFF的计数器开始,则下一个值将改变计数器的第33个最低有效位)。

然后,我宁愿选择一个8字节的随机数,并将最低有效位设置为全零。 或者当然选择GCM模式。


certificate:

 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)); 

输出:

 66e94bd4ef8a2c3b884cfa59ca342b2e 66e94bd4ef8a2c3b884cfa59ca342b2e