[英]Difference between IvParameterSpec and GCMParameterSpec with AES/GCM/NoPadding
我使用AES/GCM/NoPadding
算法加密Android上的一些數據(API 19及以后版本),然后再將其解密。
我使用的密鑰大小是32字節,並提供給我
除了加密, 我還想知道我何時嘗試解密並使用錯誤的密鑰 。 這就是為什么我更喜歡使用GCM作為我的模式來獲得驗證完整性的好處(我相信可以安全地假設密文或密鑰中的哪一個是錯誤的會導致解密異常而不是亂碼文本)
我面臨的問題是在Android API 19上使用上面的算法並使用GCMParameterSpec
初始化密碼我得到NoSuchAlgorithmException
,我沒有指定任何提供者自己允許Android為我選擇一個可以支持我的算法。 21+以上的算法可用。 這就是我初始化的方法(類似於解密),整個課程在本文末尾發布。
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key, "AES"), new GCMParameterSpec(TAG_LENGTH_BIT, iv));
但是,如果我使用IvParameterSpec(iv)
作為我的AlgorithmParameters
而不是GCMParameterSpec
那么代碼工作正常。
那么通過改變這些參數會發生什么? 我仍然可以獲得GCM的所有好處嗎?
因為在嘗試使用錯誤的密鑰時拋出的異常是不同的。 在API 19上,當使用IvParameterSpec
時拋出BadPaddingException
,在API 21+上使用AEADBADTagException
拋出GCMParameterSpec
。
通過所有Android API級別僅使用IvParameterSpec
並通過BadPaddingException
驗證完整性是否正確和安全? 我不想為不同的平台有不同的實現,所以我只想使用一個。
此外,在API 21+上,如果我使用GCMParameterSpec
加密,然后使用IvParameterSpec
解密它解密就好了! 反之亦然。 這怎么樣?
如果在API 19上無法實現上述目標,那么我可以選擇使用哪種加密算法和策略( AES/CBC/PKCS5Padding
與HMAC?)來驗證密鑰的完整性。
全班代碼:
import android.util.Base64;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.util.Arrays;
import javax.crypto.Cipher;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
final class Encryption {
private static final String ALGORITHM = "AES/GCM/NoPadding";
private static final int TAG_LENGTH_BIT = 128;
private static final int IV_LENGTH_BYTE = 12;
private final SecureRandom secureRandom;
private Cipher cipher;
private final Charset charset = StandardCharsets.UTF_8;
public Encryption() {
secureRandom = new SecureRandom();
}
public String encrypt(byte[] key, String rawData) throws Exception {
try {
byte[] iv = new byte[IV_LENGTH_BYTE];
secureRandom.nextBytes(iv);
cipher = Cipher.getInstance(ALGORITHM);
//This is where I switch to IvParameterSpec(iv)
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key, "AES"), new GCMParameterSpec(TAG_LENGTH_BIT, iv));
byte[] encrypted = cipher.doFinal(rawData.getBytes(charset));
ByteBuffer byteBuffer = ByteBuffer.allocate(1 + iv.length + encrypted.length);
byteBuffer.put((byte) iv.length);
byteBuffer.put(iv);
byteBuffer.put(encrypted);
return Base64.encodeToString(byteBuffer.array(), Base64.NO_WRAP);
} catch (Exception e) { //ignore this SO
throw new Exception(e);
}
}
public String decrypt(byte[] key, String encryptedData) throws Exception {
try {
ByteBuffer byteBuffer = ByteBuffer.wrap(Base64.decode(encryptedData, Base64.NO_WRAP));
int ivLength = byteBuffer.get();
byte[] iv = new byte[ivLength];
byteBuffer.get(iv);
byte[] encrypted = new byte[byteBuffer.remaining()];
byteBuffer.get(encrypted);
cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key, "AES"), new GCMParameterSpec(TAG_LENGTH_BIT, iv));
byte[] decrypted = cipher.doFinal(encrypted);
//Paranoia
Arrays.fill(iv, (byte) 0);
Arrays.fill(rawEncryptionKey, (byte) 0);
Arrays.fill(encrypted, (byte) 0);
return new String(decrypted, charset);
} catch (Exception e) { //ignore this SO
// On API 19 BadPaddingException is thrown when IvParameterSpec is used
// On API 21+ AEADBADTagException is thrown
throw new Exception("could not decrypt", e);
}
}
}
另外,請隨意建議改進所提供的課程以及您的答案,謝謝。
我也想知道我何時嘗試解密並使用錯誤的密鑰。
這沒關系,但請理解,無效標簽可能意味着標簽本身被更改,密文被更改,IV被更改,AAD被更改或確實密鑰不正確。
您還可以使用密鑰檢查值或類似的東西來檢查密鑰大小是否正確,然后再進行解密。 但請注意,對手也可以改變該檢查值。
那么通過改變這些參數會發生什么? 我仍然可以獲得GCM的所有好處嗎?
可以肯定的是,GCM的改造方式基本上是兼容的,但仍然有更多的配置選項(主要是標簽尺寸) - 如果你需要配置它。 AEADBADTagException
是BadPaddingException
因此代碼應該適用於每個,即使AEADBADTagException
更具體。
通過所有Android API級別僅使用
IvParameterSpec
並通過BadPaddingException
驗證完整性是否正確和安全? 我不想為不同的平台有不同的實現,所以我只想使用一個。
當然。 請注意,只有標記可能會拋出BadPaddingException
,因此這樣的異常會正確識別身份驗證問題。
此外,在API 21+上,如果我使用GCMParameterSpec加密,然后使用IvParameterSpec解密它解密就好了! 反之亦然。 這怎么樣?
您的代碼針對每種類型的參數規范運行,因為您指定的標記大小與默認值相同:128位。 它不適用於較小的標簽大小。
代碼評論:
charset
應該是一個常數( static final
); SecretKey
實例傳遞; ArrayIndexOutOfBounds
異常);
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.