[英]Java AES CTR IV and counter
我試着找到答案,自己看這里並在別處搜索了一段時間,但我還是有一些問題。
假設這個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);
}
我的問題是:
對於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); }
我有更多與修改的while循環方法有關的問題。 以這種方式調用cipher.init()可以嗎? 我這樣做是因為我還沒有找到一種方法來更新IV(計數器真的)。
是如此大的塊大小還是應該變小? 在那種情況下它應該有多大?
- 對於CTR模式的計數器更新,上述代碼是否正常?
是。
但是你可能想要調整一下nonce和counter大小。 如果你的nonce只有64位長,那么由於生日悖論,你可能會在2 32次加密后遇到nonce沖突(如果接近那個點,概率會增加)。 如果你對所有這些加密使用相同的密鑰(我的意思是消息/文件不是塊)並且存在沖突,這被認為是CTR模式的災難性中斷,因為它是兩次或多次填充。
您應該考慮使用96位隨機數和32位計數器。 缺點是您最多只能安全加密2 個32塊,每個消息/文件大小為68 GB。
- 我有更多與修改的while循環方法有關的問題。 以這種方式調用cipher.init()可以嗎?
沒有。
你真的不應該自己更新計數器。 請注意,字節和塊密碼塊之間存在不匹配:建議的計數器更新使用已作為新計數器值處理的字節,其速度比按塊計數的自然CTR模式計數器快得多。 你正在耗盡計數器,以便更容易發生碰撞。 例如,如果在數字表示時,隨機數相差1,則如果nonce部分較短且計數器部分較長,則可能發生重疊。 如果nonce是96位長,那么你只能安全地加密大小為68/16 GB = 4.5 GB的消息/文件。
此外,由於您的字節/塊不匹配,這不再是CTR模式,您將很難將此代碼移植到其他語言。
- 是如此大的塊大小還是應該變小? 在那種情況下它應該有多大?
不確定你的意思,AES的固定塊大小為128位或16字節。
如果您的意思是輸入/輸出緩沖區,那么您應該在您選擇的平台上對其進行基准測試以確定。 它當然看起來不錯。
而不是像你在這里那樣生成iv / nonce:
// 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);
您應該考慮執行以下操作:
Cipher cipher = Cipher.getInstance("AES/CTR/NoPadding");
// By doing this here w/o an IvParameterSpec, you let the
// cipher initialization create it. Less chance (see what I did there)
// to influence values that should be completely random.
cipher.init(cipherMode, secretKey);
AlgorithmParameters ivSpec = cipher.getParameters();
byte[] nonceAndCounter= ivSpec.getEncoded()
在接收端,當您需要從返回到nonceAndCounter的值構造IvParameterSpec時,然后構建您的解密模式。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.