我目前正在Android上实现使用AES 256对称加密/解密,受这篇文章的启发:Java 256bit AES Encryption。我的实现目的是要加密数据库中的数据。
为了生成密钥,我使用以下构造函数,它接受一个char[]密码:
当我在Android中启动我的Activity时,我初始化了一个新的Cryptography类实例,从而获得一个生成的密钥。盐是一个固定的随机字节数组,长度为16个字节。这意味着我总是得到相同的密钥。稍后会解释原因。
现在,在一个Activity中获取了一个对象后,我可以使用以下加密和解密方法,始终使用相同的密钥:
正如您所看到的,每次加密消息时,我都会保存一个新的IV和密文。
总之:我在数据库表中的每个字段中使用一个加密密钥、一个随机盐和一个新的IV。
起初,我想每次加密数据库表中的一个字段时都生成一个新的密钥、一个新的盐和一个新的IV,并将所需的盐和IV与密文一起保存,或者至少对于一个表行。但我之所以像上面提到的那样做,是因为在Android设备上生成密钥需要太长时间了。我在模拟器上测试了它,但生成密钥大约需要两秒钟。这就是为什么我只在Activity启动时生成一个密钥。
所以最后我的问题是: 采用我的方法,仅使用一个密钥,但每条消息都使用新的随机IV,是否足够安全?目前,我没有看到其他方法可以在保持性能平衡的同时使其尽可能安全。
我希望我写的足够清楚,有人可以给我一些建议。
此致敬礼
xoidberg
为了生成密钥,我使用以下构造函数,它接受一个char[]密码:
public Cryptography(char[] password) throws NoSuchAlgorithmException,
InvalidKeySpecException, NoSuchPaddingException {
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBEWITHSHA256AND256BITAES-CBC-BC");
KeySpec spec = new PBEKeySpec(password, salt, 1024, 256);
secretKey = new SecretKeySpec(factory.generateSecret(spec).getEncoded(), "AES");
cipher = Cipher.getInstance(AES/CBC/PKCS5Padding);
}
当我在Android中启动我的Activity时,我初始化了一个新的Cryptography类实例,从而获得一个生成的密钥。盐是一个固定的随机字节数组,长度为16个字节。这意味着我总是得到相同的密钥。稍后会解释原因。
现在,在一个Activity中获取了一个对象后,我可以使用以下加密和解密方法,始终使用相同的密钥:
public byte[] encrypt(String cleartext) throws InvalidKeyException,
IllegalBlockSizeException, BadPaddingException,
UnsupportedEncodingException, InvalidParameterSpecException {
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
byte[] encText = cipher.doFinal(cleartext.getBytes(CHARSET_NAME));
byte[] iv = cipher.getParameters()
.getParameterSpec(IvParameterSpec.class).getIV();
byte[] enc = new byte[IV_SIZE + encText.length];
for (int i = 0; i < enc.length; i++) {
if (i < IV_SIZE)
enc[i] = iv[i];
else if (i < enc.length)
enc[i] = encText[i - IV_SIZE];
}
return enc;
}
public String decrypt(byte[] encryptedText) throws InvalidKeyException,
InvalidAlgorithmParameterException, UnsupportedEncodingException,
IllegalBlockSizeException, BadPaddingException {
byte[] iv = new byte[IV_SIZE];
byte[] dec = new byte[encryptedText.length - IV_SIZE];
for (int i = 0; i < encryptedText.length; i++) {
if (i < IV_SIZE)
iv[i] = encryptedText[i];
else if (i < encryptedText.length)
dec[i - IV_SIZE] = encryptedText[i];
}
cipher.init(Cipher.DECRYPT_MODE, secretKey, new IvParameterSpec(iv));
return new String(cipher.doFinal(dec), CHARSET_NAME);
}
正如您所看到的,每次加密消息时,我都会保存一个新的IV和密文。
总之:我在数据库表中的每个字段中使用一个加密密钥、一个随机盐和一个新的IV。
起初,我想每次加密数据库表中的一个字段时都生成一个新的密钥、一个新的盐和一个新的IV,并将所需的盐和IV与密文一起保存,或者至少对于一个表行。但我之所以像上面提到的那样做,是因为在Android设备上生成密钥需要太长时间了。我在模拟器上测试了它,但生成密钥大约需要两秒钟。这就是为什么我只在Activity启动时生成一个密钥。
所以最后我的问题是: 采用我的方法,仅使用一个密钥,但每条消息都使用新的随机IV,是否足够安全?目前,我没有看到其他方法可以在保持性能平衡的同时使其尽可能安全。
我希望我写的足够清楚,有人可以给我一些建议。
此致敬礼
xoidberg