我正在使用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 BadPaddingException
时抛出API 19 IvParameterSpec
,使用API AEADBADTagException
时抛出API 21+ GCMParameterSpec
。
仅IvParameterSpec
通过所有Android API级别使用并通过验证完整性是否正确和安全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
是更具体的。
仅
IvParameterSpec
通过所有Android API级别使用并通过验证完整性是否正确和安全BadPaddingException
?我不想为不同的平台使用不同的实现,所以我只想使用一个。
当然。请注意,只有标签可以引发BadPaddingException
,因此此类异常可以正确识别身份验证问题。
另外,在API 21+上,如果我使用GCMParameterSpec进行加密,然后再使用IvParameterSpec对其进行解密,则可以解密!反之亦然。怎么运作的?
您的代码针对每种类型的参数规范运行,因为您指定的标签大小与默认值相同:128位。较小的标签尺寸将无法使用。
代码注释:
charset
应该是一个常量(static final
);SecretKey
实例传递;ArrayIndexOutOfBounds
异常);本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句