如何处理 AES CTR 的 IV/Nonce/Counter?
How to handle the IV/Nonce/Counter for AES CTR?
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 Recommendation - 附录 B,有两种构造初始计数器块的有效方法(AES 是 128 位块密码):
- 128 位随机数与 m 位计数器值(通常为 32 位)异或。
- 64 位随机数附加到 64 位计数器。
我的问题是:
- 关于使用的初始计数器块的确切过程是什么
在 javax.crypto.Cipher 的“AES/CTR/NoPadding”实例中(假设 SunJCE 作为提供者)?
也就是说,给定上面的代码,如果有的话,使用了以前的哪种初始计数器块方法?
Java 只是让您选择构建计数器的方式。您只需要使用 16 字节的 IV 初始化 CTR 模式,它只不过是初始计数器值。
一旦您开始加密,它将在整个 128 位上使用一个计数器。话又说回来,您几乎不希望它重新开始,因为这会直接危及明文的安全性。缺点是不直接支持 32 位 XOR 方法(如果您从 FFFFFFFF
的计数器开始,下一个值将改变计数器的第 33 个最低有效位)。
话又说回来,我宁愿选择一个 8 字节的随机数并将最低有效位设置为全零。或者当然选择GCM模式。
证明:
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
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 Recommendation - 附录 B,有两种构造初始计数器块的有效方法(AES 是 128 位块密码):
- 128 位随机数与 m 位计数器值(通常为 32 位)异或。
- 64 位随机数附加到 64 位计数器。
我的问题是:
- 关于使用的初始计数器块的确切过程是什么 在 javax.crypto.Cipher 的“AES/CTR/NoPadding”实例中(假设 SunJCE 作为提供者)? 也就是说,给定上面的代码,如果有的话,使用了以前的哪种初始计数器块方法?
Java 只是让您选择构建计数器的方式。您只需要使用 16 字节的 IV 初始化 CTR 模式,它只不过是初始计数器值。
一旦您开始加密,它将在整个 128 位上使用一个计数器。话又说回来,您几乎不希望它重新开始,因为这会直接危及明文的安全性。缺点是不直接支持 32 位 XOR 方法(如果您从 FFFFFFFF
的计数器开始,下一个值将改变计数器的第 33 个最低有效位)。
话又说回来,我宁愿选择一个 8 字节的随机数并将最低有效位设置为全零。或者当然选择GCM模式。
证明:
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