【发布时间】:2015-12-29 08:18:36
【问题描述】:
我正在尝试在 Android 中实现 AES 加密,它使用密码生成SecretKey。我通过了同样的byte[]
作为密码的初始化向量和使用 PBKDF2 生成 SecretKey 时的盐。
用户每次需要加密/解密时都会提供密码。
到目前为止,我只需要在我的数据库中加密一个值(如果这有什么不同的话)。
问题:
- 我想知道是否使用与 IV 相同的
byte[]和 salt 会削弱加密? - 除了 GCM 提供的数据完整性功能之外,是否还有理由从 CBC 切换到 GCM?
- 我了解到 CBC 容易受到 BEAST 攻击,如下所示,每条消息使用新的随机 IV 来缓解 BEAST 攻击?
当前源代码:
public class AesEncryption {
private static final int KEY_SIZE = 16;
private static final int OUTPUT_KEY_LENGTH = 256;
private static final int ITERATIONS = 1000;
private String mPassphraseOrPin;
public AesEncryption(String passphraseOrPin) {
mPassphraseOrPin = passphraseOrPin;
}
public void encrypt(String id, String textToEncrypt) throws Exception {
byte[] iv = getIv();
SecretKey secretKey = generateKey(iv);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secretKey, new IvParameterSpec(iv));
byte[] cipherText = cipher.doFinal(textToEncrypt.getBytes("utf-8"));
byte[] ivCipherText = arrayConcat(iv, cipherText);
String encryptedText = Base64.encodeToString(ivCipherText, Base64.NO_WRAP);
storeEncryptedTextInDb(id, encryptedText);
}
public String decrypt(String id) throws Exception {
String encryptedText = getEncryptedTextFromDb(id);
byte[] ivCipherText = Base64.decode(encryptedText, Base64.NO_WRAP);
byte[] iv = Arrays.copyOfRange(ivCipherText, 0, KEY_SIZE);
byte[] cipherText = Arrays.copyOfRange(ivCipherText, KEY_SIZE, ivCipherText.length);
SecretKey secretKey = generateKey(iv);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, secretKey, new IvParameterSpec(iv));
String decrypted = new String(cipher.doFinal(cipherText), "utf-8");
return decrypted;
}
public SecretKey generateKey(byte[] salt) throws Exception {
SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
KeySpec keySpec = new PBEKeySpec(mPassphraseOrPin.toCharArray(), salt, ITERATIONS, OUTPUT_KEY_LENGTH);
SecretKey tmp = secretKeyFactory.generateSecret(keySpec);
return new SecretKeySpec(tmp.getEncoded(), "AES");
}
private byte[] getIv() {
byte[] salt = new byte[KEY_SIZE];
new SecureRandom().nextBytes(salt);
return salt;
}
private byte[] arrayConcat(byte[] one, byte[] two) {
byte[] combined = new byte[one.length + two.length];
for (int i = 0; i < combined.length; ++i) {
combined[i] = i < one.length ? one[i] : two[i - one.length];
}
return combined;
}
}
【问题讨论】:
-
我假设是本地 Android 数据库?
-
@MaartenBodewes 是的。我正在考虑将加密文本保存到 SharedPreferences 中。
-
好的,在这种情况下,传输中的数据不会受到攻击(例如,CBC padding oracle 攻击)。不幸的是,我无法进行全面的安全审查——答案不是那样。一般来说,看看平台本身提供的保护选项是值得的。
标签: android cryptography aes cbc-mode aes-gcm